NotSerializableException on SimpleListProperty

后端 未结 6 1893
予麋鹿
予麋鹿 2020-12-10 08:09

I\'m using Javafx, and I wrap my objects into ListProperty to let the tableview updates for any changes on the objects of the list. Now I\'m trying to serialize my project a

6条回答
  •  一整个雨季
    2020-12-10 08:54

    Here is the solution that works for me (Serialize SimpleXXXProperty on a JPA Entity where xxx can be String, Object, etc)

    https://gist.github.com/james-d/a7202039b00170256293

    You 'just' have to :
    1) implements Serializable
    2) set all Properties as transient
    3) define 2 specials methodes like that :

    private void writeObject(ObjectOutputStream s) throws IOException {
        s.defaultWriteObject();
        s.writeLong(idProperty().longValue());
        s.writeUTF(aStringProperty().getValueSafe()); // can't be null so use getValueSafe that returns empty string if it's null
        s.writeUTF(anOtherStringPoperty().getValueSafe());
    }
    

    and

    private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
        idProperty.set(s.readLong());
        aStringProperty.set(s.readUTF());
        anOtherStringPoperty(s.readUTF());
        // set values in the same order as writeObject()
    }
    

    and voilà :) You can serialize your Object with

    MyObject o = new MyObject();
    ObjectOutputStream oos = new ObjectOutputStream(baos);
    oos.writeObject(o);
    oos.close();
    

    Note that these strange private methodes are directly called by the Java Virtual Machine and must not be Override, public or other as mentionned in the official documentation.

    Edited : don't use writeChars for String but writeUTF.
    And remember that on deserialization process, the "readed object" isn't instanciated (constructor isn't called!) and then all Properties aren't initialized and so idProperty.set(o) will throws nullPointerException.
    So you have to create a initMethode where all properties are initialized. Call this methode from your constructor AND from readObject methode before read data from the ObjectInputStream

    Edit : I made helpers for automatic write and read. Here is code if you want to use it :

    public class WriteObjectsHelper {
    
    // write a StringProperty to ObjectOutputStream
    public static void writeStringProp(ObjectOutputStream s, StringProperty strProp) throws IOException {
        s.writeUTF(strProp.getValueSafe());
    }
    
    // write a ListProperty to ObjectOutputStream
    public static void writeListProp(ObjectOutputStream s, ListProperty lstProp) throws IOException {
        if(lstProp==null || lstProp.getValue()==null) {
            s.writeInt(0);
            return;
        }
        s.writeInt(lstProp.size());
        for(Object elt:lstProp.getValue()) s.writeObject(elt);
    }
    
    // automatic write set of properties to ObjectOutputStream
    public static void writeAllProp(ObjectOutputStream s, Property... properties) throws IOException {
        s.defaultWriteObject();
        for(Property prop:properties) {
            if(prop instanceof IntegerProperty) s.writeInt(((IntegerProperty) prop).intValue());
            else if(prop instanceof LongProperty) s.writeLong(((LongProperty) prop).longValue());
            else if(prop instanceof StringProperty) s.writeUTF(((StringProperty)prop).getValueSafe());
            else if(prop instanceof BooleanProperty) s.writeBoolean(((BooleanProperty)prop).get());
            else if(prop instanceof ListProperty) writeListProp(s,(ListProperty)prop);
            else if(prop instanceof ObjectProperty) s.writeObject(((ObjectProperty) prop).get());
            else throw new RuntimeException("Type d'objet incompatible : " + prop.toString());
        }
    }
    }
    
    public class ReadObjectsHelper {
    
    // Read a ListProperty from ObjectInputStream (and return it)
    public static ListProperty readListProp(ObjectInputStream s) throws IOException, ClassNotFoundException {
        ListProperty lst=new SimpleListProperty(FXCollections.observableArrayList());
        int loop=s.readInt();
        for(int i = 0;i

    And them, here is part of my (french) JPA entity :

    @Entity
    @Table(name="articles")
    public class Article implements Serializable, IEntity {
    
    private transient LongProperty idArticle;
    public LongProperty idArticleProperty() { return idArticle; }
    
    private transient StringProperty descriptionFr;
    public StringProperty descriptionFrProperty() { return descriptionFr; }
    
    private transient StringProperty reference;
    public StringProperty referenceProperty() { return reference; }
    
    private transient StringProperty constructeur;
    public StringProperty constructeurProperty() { return constructeur; }
    
    private transient StringProperty numSAP;
    public StringProperty numSAPProperty() { return numSAP; }
    
    private transient StringProperty descriptionEn;
    public StringProperty descriptionEnProperty() { return descriptionEn; }
    
    private transient ListProperty
    testList; public ListProperty
    articlesProperty() {return testList; } public Article() { initInstance(); } /** * Need for calling by readObject; */ private void initInstance() { idArticle=new SimpleLongProperty(); descriptionFr=new SimpleStringProperty(); descriptionEn=new SimpleStringProperty(); reference=new SimpleStringProperty(); constructeur=new SimpleStringProperty(); numSAP=new SimpleStringProperty(); testList=new SimpleListProperty<>(FXCollections.observableArrayList()); } private void writeObject(ObjectOutputStream s) throws IOException { WriteObjectsHelper.writeAllProp(s,idArticle,descriptionFr,reference,constructeur,numSAP,descriptionEn,testList); } private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { initInstance(); ReadObjectsHelper.readAllProp(s, idArticle,descriptionFr,reference,constructeur,numSAP,descriptionEn,testList); } @Column(name = "idArticle") @Id @GeneratedValue(strategy = GenerationType.IDENTITY) public Long getIdArticle() { return idArticle.get(); } public void setIdArticle(Long idArticle) { this.idArticle.set(idArticle); } //... }

提交回复
热议问题