Skip to content

Fails to internalize ObservableList #1

@MichaelEllis

Description

@MichaelEllis

Starting with a simple class for a person

package xstreamfxextensions;

import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamImplicit;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

@XStreamAlias("Person")   //define class level alias
public class Person {

    @XStreamAlias("Sex")
    public enum Sex {

        MALE, FEMALE, UNKNOWN, OTHER
    };

    public StringProperty name = new SimpleStringProperty(this, "name", "nameless");
    public IntegerProperty age = new SimpleIntegerProperty(this, "age", 0);
    public ObjectProperty<Sex> sex = new SimpleObjectProperty<>(this, "sex", Sex.MALE);

    public ObservableList<Person> children  = FXCollections.<Person>observableArrayList();

    public Person(String name, int age, Sex sex) {
        this.name.set(name);
        this.age.set(age);
        this.sex.set(sex);
    }

    @Override
    public String toString() {
        return "Person{"
                + "name=" + name.get()
                + ", age=" + age.get()
                + ", sex=" + sex.get()
                + ", children=" + children
                + '}';
    }

}

A simple test class to use XStream and XStreamFX to externalise and internalise some people.

package xstreamfxextensions;

import com.dooapp.xstreamfx.FXConverters;
import com.sun.javafx.collections.ObservableListWrapper;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.StaxDriver;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleFloatProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleListProperty;
import javafx.beans.property.SimpleLongProperty;
import javafx.beans.property.SimpleMapProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleSetProperty;
import javafx.beans.property.SimpleStringProperty;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.stream.StreamResult;
import org.junit.Test;
import org.xml.sax.InputSource;
import xstreamfxextensions.Person.Sex;

public class XStreamFXExtensionsTest {

    /**
     * Add XStream aliases for common JavaFX types
     *
     * @param xstream
     */
    public static void addFXAliases(XStream xstream) {
        Class[] cs = new Class[]{
            ObservableListWrapper.class,

            // The Simple... properties
            SimpleStringProperty.class,
            SimpleIntegerProperty.class,
            SimpleObjectProperty.class,
            SimpleFloatProperty.class,
            SimpleBooleanProperty.class,
            SimpleListProperty.class,
            SimpleLongProperty.class,
            SimpleMapProperty.class,
            SimpleSetProperty.class,
            SimpleFloatProperty.class,};

        for (Class c : cs) { // 
            // Alias the class's simple name to its pull name
            xstream.alias(c.getSimpleName(), c);
        }
    }

    @Test
    public void testSXtreamPerson() throws IOException {
        XStream xstream = new XStream(new StaxDriver());
        Person fred = new Person("Fred", 71, Sex.MALE);
        fred.children.add(new Person("Paul", 21, Sex.MALE));
        fred.children.add(new Person("James", 20, Sex.MALE));
        fred.children.add(new Person("Angela", 20, Sex.FEMALE));

        xstream.autodetectAnnotations(true);
        FXConverters.configure(xstream);
        addFXAliases(xstream);

        //Object to XML Conversion
        String xml = formatXml(xstream.toXML(fred));
        Files.write(Paths.get("PeopleImplicit.xml"), xml.getBytes());

        //XML to Object Conversion
        Person a = (Person) xstream.fromXML(xml);
        System.out.println(a);
    }

    public static String formatXml(String xml) {
        try {
            Transformer serializer = SAXTransformerFactory.newInstance().newTransformer();
            serializer.setOutputProperty(OutputKeys.INDENT, "yes");
            serializer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
            Source xmlSource = new SAXSource(new InputSource(new ByteArrayInputStream(xml.getBytes())));
            StreamResult res = new StreamResult(new ByteArrayOutputStream());
            serializer.transform(xmlSource, res);
            return new String(((ByteArrayOutputStream) res.getOutputStream()).toByteArray());
        } catch (Exception e) {
            return xml;
        }
    }

}

Running this results in error:

Testcase: testSXtreamPerson(xstreamfxextensions.XStreamFXExtensionsTest):   Caused an ERROR
Cannot instantiate com.sun.javafx.collections.ObservableListWrapper : com.sun.javafx.collections.ObservableListWrapper
---- Debugging information ----
message             : Cannot instantiate com.sun.javafx.collections.ObservableListWrapper
cause-exception     : java.lang.InstantiationException
cause-message       : com.sun.javafx.collections.ObservableListWrapper
class               : com.sun.javafx.collections.ObservableListWrapper
required-type       : com.sun.javafx.collections.ObservableListWrapper
converter-type      : com.dooapp.xstreamfx.ObservableListConverter
path                : /Person/children
line number         : 5
class[1]            : xstreamfxextensions.Person
converter-type[1]   : com.thoughtworks.xstream.converters.reflection.ReflectionConverter
version             : 1.4.8
-------------------------------
com.thoughtworks.xstream.converters.ConversionException: Cannot instantiate com.sun.javafx.collections.ObservableListWrapper : com.sun.javafx.collections.ObservableListWrapper
---- Debugging information ----
message             : Cannot instantiate com.sun.javafx.collections.ObservableListWrapper
cause-exception     : java.lang.InstantiationException
cause-message       : com.sun.javafx.collections.ObservableListWrapper
class               : com.sun.javafx.collections.ObservableListWrapper
required-type       : com.sun.javafx.collections.ObservableListWrapper
converter-type      : com.dooapp.xstreamfx.ObservableListConverter
path                : /Person/children
line number         : 5
class[1]            : xstreamfxextensions.Person
converter-type[1]   : com.thoughtworks.xstream.converters.reflection.ReflectionConverter
version             : 1.4.8
-------------------------------
    at com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter.createCollection(AbstractCollectionConverter.java:79)
    at com.thoughtworks.xstream.converters.collections.CollectionConverter.createCollection(CollectionConverter.java:103)
    at com.dooapp.xstreamfx.ObservableListConverter.createCollection(ObservableListConverter.java:40)
    at com.thoughtworks.xstream.converters.collections.CollectionConverter.unmarshal(CollectionConverter.java:79)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72)
    at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66)
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:480)
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:412)
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:263)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72)
    at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:50)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:134)
    at com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal(AbstractTreeMarshallingStrategy.java:32)
    at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1206)
    at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1190)
    at com.thoughtworks.xstream.XStream.fromXML(XStream.java:1061)
    at com.thoughtworks.xstream.XStream.fromXML(XStream.java:1052)
    at xstreamfxextensions.XStreamFXExtensionsTest.testSXtreamPerson(XStreamFXExtensionsTest.java:77)
Caused by: java.lang.InstantiationException: com.sun.javafx.collections.ObservableListWrapper
    at java.lang.Class.newInstance(Class.java:427)
    at com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter.createCollection(AbstractCollectionConverter.java:77)
Caused by: java.lang.NoSuchMethodException: com.sun.javafx.collections.ObservableListWrapper.<init>()
    at java.lang.Class.getConstructor0(Class.java:3082)
    at java.lang.Class.newInstance(Class.java:412)

I found modifying ObservableListConverter to

package com.dooapp.xstreamfx;

import com.sun.javafx.collections.ObservableListWrapper;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.collections.CollectionConverter;
import com.thoughtworks.xstream.mapper.Mapper;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import xstreamfxextensions.Person;

/**
 * TODO write documentation<br>
 * <br>
 * Created at 21/09/11 09:32.<br>
 *
 * @author Antoine Mischler <[email protected]>
 * @since 2.2
 */
public class ObservableListConverter extends CollectionConverter implements Converter {

    public ObservableListConverter(Mapper mapper) {
        super(mapper);
    }

    @Override
    public boolean canConvert(Class type) {
        return ObservableList.class.isAssignableFrom(type);
    }

    @Override
    protected Object createCollection(Class type) {
        if (type == ObservableListWrapper.class) {
            return FXCollections.<Person>observableArrayList();
        }
        return super.createCollection(type);
    }
}

Explanation: ObservableListWrapper does not have a no argument constructor but has to be created with the FXCollections.observableArrayList() factory method.

So all well and good...

Until you try to to mark the collection with @XStreamImplicit In which case you get the same problem.

Any help with this gratefully appreciated!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions