Search code examples
javamongodbenumsinner-classesmorphia

Morphia can't insert class into DB


I want to strore Object to MongoDB with Morphia.

But I got bunch of exceptions:

Exception in thread "main" java.lang.IllegalArgumentException: can't serialize class com.aerlingus.ta.models.b2b.faresearch.AirSearchPrefsType$CabinPref
    at org.bson.BasicBSONEncoder._putObjectField(BasicBSONEncoder.java:270)

Here is this save():

public void create(MODEL model) {
    Object keyValue = get(model);
    if(datastore.find(this.model).field(keyField.id()).equal(keyValue).get() == null){
        datastore.save(model);
    } else {
        throw new RuntimeException(String.format("Duplicate parameters '%s' : '%s'", keyField.id(), keyValue));
    }
}

Here is AirSearchPrefsType class:

@Embedded
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "")
public static class CabinPref {

    @Embedded @Compare
    @XmlAttribute(name = "PreferLevel")
    protected PreferLevelType preferLevel;

    @Embedded @Compare
    @XmlAttribute(name = "Cabin")
    protected CabinType cabin;

    @Transient
    @XmlAttribute(name = "CabinSubtype")
    protected String cabinSubtype;

and PreferLevelType:

@Embedded
@XmlType(name = "PreferLevelType")
@XmlEnum
public enum PreferLevelType {

    @Embedded
    @XmlEnumValue("Only")
    ONLY("Only"),

    @XmlEnumValue("Unacceptable")
    @Embedded
    UNACCEPTABLE("Unacceptable"),

    @XmlEnumValue("Preferred")
    @Embedded
    PREFERRED("Preferred"),

    @Embedded
    @XmlEnumValue("Required")
    REQUIRED("Required"),

    @Embedded
    @XmlEnumValue("NoPreference")
    NO_PREFERENCE("NoPreference");
    private final String value;

and CabinType:

@Embedded
@XmlType(name = "CabinType")
@XmlEnum
public enum CabinType {

    @XmlEnumValue("First")
    FIRST("First"),

    @XmlEnumValue("Business")
    BUSINESS("Business"),

    @XmlEnumValue("Economy")
    ECONOMY("Economy");
    private final String value;

I couldn't understand what is wrong here. Does Morphia wiorks with static inner classes or with enums.

How to solve this trouble?


Solution

  • The following code will show exceptions like yours:

    package com.test.mongodb;
    
    import java.io.IOException;
    import java.io.Serializable;
    
    import org.junit.Test;
    
    import com.mongodb.BasicDBObject;
    import com.mongodb.DBCollection;
    import com.mongodb.MongoClient;
    
    public class TestMongo {
    
        static class Temp implements Serializable {
    
            private static final long serialVersionUID = 1L;
            private String name;
    
            public Temp(String name) {
                this.name = name;
            }
    
            public String getName() {
                return name;
            }
        }
    
        @Test
        public void test() {
            try {
                MongoClient mongoClient = new MongoClient();
                DBCollection collection = mongoClient.getDB("test").getCollection("temp");
    
                Temp temp = new Temp("Current time: " + System.currentTimeMillis());
    
                collection.insert(new BasicDBObject("JavaObject", temp));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    You can try this way:

    package com.test.mongodb;
    
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.io.Serializable;
    
    import org.junit.Test;
    
    import com.mongodb.BasicDBObject;
    import com.mongodb.DBCollection;
    import com.mongodb.DBCursor;
    import com.mongodb.DBObject;
    import com.mongodb.MongoClient;
    
    public class TestMongo {
    
        static class Temp implements Serializable {
    
            private static final long serialVersionUID = 1L;
            private String name;
    
            public Temp(String name) {
                this.name = name;
            }
    
            public String getName() {
                return name;
            }
        }
    
        @Test
        public void test(){
            try {
                MongoClient mongoClient = new MongoClient();
                DBCollection collection = mongoClient.getDB("test").getCollection("temp");
    
                Temp temp = new Temp("Currect time: " + System.currentTimeMillis());
    
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                ObjectOutputStream oos = new ObjectOutputStream(baos);
                oos.writeObject(temp);
                collection.insert(new BasicDBObject("JavaObject", baos.toByteArray()));
    
                readObject(collection);
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }
    
        /**
         * read the java object from mongodb
         * @param collection
         */
        public void readObject(DBCollection collection){
            try {
                DBCursor cursor = collection.find();
                for (DBObject dbObject : cursor) {
                    ByteArrayInputStream bais = new ByteArrayInputStream((byte[]) dbObject.get("JavaObject"));
                    ObjectInputStream ois = new ObjectInputStream(bais);
                    Temp temp = (Temp) ois.readObject();
                    System.out.println(temp.getName());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    This approach doesn't conform to Morphia exactly, but to Mongo itself.