google-code-export / morphia

Automatically exported from code.google.com/p/morphia
1 stars 0 forks source link

no Classname Stored for @Embedded #293

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
What version are you using? (Morphia/Driver/MongoDB) 1.0 Snapshot /2.6.3 /1.8.2

Please include a stack trace below:

My testing codes: 

@Test
    public void addPhoneNumberUsingMorphia() {
        // /DBCollection hotels = db.getCollection("hotels");
        morphia.map(Hotel.class);
        Query<Hotel> updateQuery = ds.createQuery(Hotel.class)
                .field(Mapper.ID_KEY).equal("4e08019cedb93eb02c873b94");
        UpdateOperations<Hotel> ops = ds.createUpdateOperations(Hotel.class)
                .add("phoneNumbers",
                        new PhoneNumber(123, 456789, PhoneNumber.Type.PHONE));
        ds.update(updateQuery, ops);
    }

@Test
    public void addPhoneNumberUsingMorphia1() {
        // /DBCollection hotels = db.getCollection("hotels");
        morphia.map(Hotel.class);
        Query<Hotel> updateQuery = ds.createQuery(Hotel.class)
                .field(Mapper.ID_KEY).equal("4e08019cedb93eb02c873b94");
        Hotel h = ds.find(Hotel.class, Mapper.ID_KEY,
                "4e08019cedb93eb02c873b94").get();
        h.getPhoneNumbers().add(
                new PhoneNumber(98, 7654321, PhoneNumber.Type.PHONE));
        UpdateOperations<Hotel> ops = ds.createUpdateOperations(Hotel.class)
                .set("phoneNumbers", h.getPhoneNumbers());
        ds.update(updateQuery, ops);
    }

Java Model:

.....
    @Transient
    private String temp;

    @Embedded
    private Address address;

    @Embedded
    private List<PhoneNumber> phoneNumbers;
...

Data In MongoDB

       {
               "className" : "com.google.code.morphia.testmodel.PhoneNumber",
               "countryCode" : 98,
               "localExtension" : 7654321,
               "type" : "PHONE"
       },
       {
               "countryCode" : 123,
               "localExtension" : 456789,
               "type" : "PHONE"
       }

Reason: 
The first method do not have className, but the second one have. The root cause 
is the way morphia to check is need classname or not, now the logic is 
encapsulated into a single method

public static boolean shouldSaveClassName(Object rawVal, Object convertedVal, 
MappedField mf) {
        if (rawVal == null || mf == null)
            return true;
        if (mf.isSingleValue())
            return !(mf.getType().equals(rawVal.getClass()) && !(convertedVal instanceof BasicDBList));
        else
            if ( convertedVal != null && 
                 convertedVal instanceof DBObject &&   (false: convertedVal is ArrayList)
                 !mf.getSubClass().isInterface() && 
                 !Modifier.isAbstract(mf.getSubClass().getModifiers()) && 
                 mf.getSubClass().equals(rawVal.getClass())) (false:  mf.getSubClass() is PhoneNumber  but rawVal.getClass() is ArrayList)
                return false;
            else 
                return true;
    }

I do not know when convertedVal instanceof DBObject  AND 
mf.getSubClass().equals(rawVal.getClass()) can be true, becuase mf is not 
SingleValue.

Original issue reported on code.google.com by j...@yottaa.com on 1 Jul 2011 at 2:14

GoogleCodeExporter commented 9 years ago
I have the exact opposite situation where the classname is recorded and (I 
think) shouldn't be. I'm guessing this is most likely related so I've attached 
my test case to this issue rather than creating another. If another issue needs 
to be created, I'll gladly do so.

In my case, if I save the entire document, the classname is not recorded as I 
expect. If instead, I update (set) the field, the classname is recorded.

Mongo/Driver/Morphia: 1.8.2/2.6.5/0.99 (also built from trunk)

public class MapTest {

    @Entity(value="foo", noClassnameStored=true)
    public static class Foo {
        @Id
        private ObjectId id;

        @Embedded("bars")
        private Map<String, Bar> bars = new HashMap<String, Bar>();
    }

    @Embedded
    public static class Bar {
        @Property("a-value")
        private String a;

        @Property("b-value")
        private String b;
    }

    public static final void main( String [] args ) throws Throwable {
        Mongo mongo = new Mongo( "localhost" );
        Morphia morphia = new Morphia();
        morphia.map( Foo.class );
        Datastore datastore = morphia.createDatastore( mongo, "test" );
        Foo foo = new Foo();
        Bar bar = new Bar();
        bar.a = "AAAA";
        bar.b = "BBBB";
        foo.bars.put( "1", bar );
        datastore.save( foo );    // works as expected

        foo = new Foo();
        datastore.save( foo );
        bar = new Bar();
        bar.a = "aaaa";
        bar.b = "bbbb";
        foo.bars.put( "2", bar );
                // records classname
        datastore.update( foo, datastore.createUpdateOperations( Foo.class ).set( "bars", foo.bars ) );
    }
}

> db.foo.find()
{ "_id" : ObjectId("4ea8ce481a8885d6d212efa0"), "bars" : { "1" : { "a-value" : 
"AAAA", "b-value" : "BBBB" } } }
{ "_id" : ObjectId("4ea8ce491a8885d6d212efa1"), "bars" : { "2" : { "className" 
: "test.mongo.morphia.MapTest$Bar", "a-value" : "aaaa", "b-value" : "bbbb" } } }

Original comment by randy.n...@gmail.com on 27 Oct 2011 at 6:10

GoogleCodeExporter commented 9 years ago
We're seeing the same issue to comment 1, with a classname being added to an 
embedded map field even though the parent entity has noClassnameStored=true.

One workaround is to add @Entity(noClassnameStored=true) on the embedded class 
(as well as @Embedded)

Original comment by one...@energyhub.net on 31 Jul 2012 at 8:36