[morphia] Embedded

246 views
Skip to first unread message

Valentín Moreno

unread,
Dec 29, 2010, 6:48:07 AM12/29/10
to mor...@googlegroups.com
Hi all:

I have these entities:

@Entity
public class MetricResult extends AuditObject {

@Indexed
private Date resultDate = null;// only non-null values are stored

@Reference
@Indexed
private Metric metric;// refs are stored*, and loaded automatically // fields can be indexed for
// better performance

private Integer lastIndex;// value types are automatically persisted

@Embedded
private Set<MetricResultParameter> parameters;

@Reference
@Indexed
private Alert alert = null;// only non-null values are stored

@Transient
private String message = null;
.....}

@Embedded
public class MetricResultParameter {

private String name;

private Object value;
....}


These dao's objects:

@Repository("metricResultDao")
public class MetricResultDaoImpl extends CommonDaoImpl<MetricResult> implements MetricResultDao {

@Autowired
public MetricResultDaoImpl(Mongo mongo, Morphia morphia, String dbName) {
super(mongo, morphia, dbName);
}

...}

public class CommonDaoImpl<T> extends BasicDAO<T, ObjectId> implements CommonDao<T, ObjectId> {

public CommonDaoImpl(Mongo mongo, Morphia morphia, String dbName) {
super(mongo, morphia, dbName);
}
... }

I don't include interfaces classes because they have only the required methods, and I think is not relevant.

When I try to retrieve all MetricResult db objects with this code:

QueryResults<MetricResult> find = metricResultDao.find();
for (MetricResult metricResult : find) {
metricResult.toString();
}

I got the next exception trace:

Exception in thread "main" java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.ClassCastException: java.lang.Double cannot be cast to com.mongodb.DBObject
at com.google.code.morphia.mapping.Mapper.fromDb(Mapper.java:413)
at com.google.code.morphia.mapping.Mapper.fromDBObject(Mapper.java:265)
at com.google.code.morphia.query.MorphiaIterator.processItem(MorphiaIterator.java:53)
at com.google.code.morphia.query.MorphiaIterator.next(MorphiaIterator.java:48)
at com.fon.rainbow.Test.main(Test.java:18)
Caused by: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.ClassCastException: java.lang.Double cannot be cast to com.mongodb.DBObject
at com.google.code.morphia.mapping.EmbeddedMapper.fromDBObject(EmbeddedMapper.java:149)
at com.google.code.morphia.mapping.Mapper.readMappedField(Mapper.java:429)
at com.google.code.morphia.mapping.Mapper.fromDb(Mapper.java:410)
... 4 more
Caused by: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.ClassCastException: java.lang.Double cannot be cast to com.mongodb.DBObject
at com.google.code.morphia.mapping.Mapper.fromDb(Mapper.java:413)
at com.google.code.morphia.mapping.EmbeddedMapper.readMapOrCollectionOrEntity(EmbeddedMapper.java:234)
at com.google.code.morphia.mapping.EmbeddedMapper.readCollection(EmbeddedMapper.java:178)
at com.google.code.morphia.mapping.EmbeddedMapper.fromDBObject(EmbeddedMapper.java:122)
... 6 more
Caused by: java.lang.RuntimeException: java.lang.ClassCastException: java.lang.Double cannot be cast to com.mongodb.DBObject
at com.google.code.morphia.mapping.EmbeddedMapper.fromDBObject(EmbeddedMapper.java:149)
at com.google.code.morphia.mapping.Mapper.readMappedField(Mapper.java:433)
at com.google.code.morphia.mapping.Mapper.fromDb(Mapper.java:410)
... 9 more
Caused by: java.lang.ClassCastException: java.lang.Double cannot be cast to com.mongodb.DBObject
at com.google.code.morphia.mapping.EmbeddedMapper.fromDBObject(EmbeddedMapper.java:139)
... 11 more



I am using morphia 0.98 version, additionally, before I started using an embedded object (Set<MetricResultParameter> parameters) on MetricResult entity, I was using a Map<String, Object> an it was working perfect.

Could one of you get me a hand with this?

Thank you in advance.
Valentín.

Michael Gray

unread,
Dec 29, 2010, 8:05:45 AM12/29/10
to mor...@googlegroups.com
Idk how that Object value inside the MetricResultParameter will map.
Can you use a real java type? Is it being set to a Double?

Sent from my iPad

Valentín Moreno

unread,
Dec 29, 2010, 9:13:36 AM12/29/10
to mor...@googlegroups.com
The problem is that I want to use this attribute as dynamic type (sometimes values will be Double others String, etc)

I this is not the real problem, because, as I explained before, I use before a HashMap<String, Object> and it worked perfect...I think is something related with Embedded feature...

Anyway thank you Michael

Scott Hernandez

unread,
Dec 29, 2010, 10:46:43 AM12/29/10
to mor...@googlegroups.com
You basically need to chose what Object is going to be. It can be
either a simple value type (String,Double,Int...) or a complex type
like a custom type. If you want the former you should use @Property to
help morphia map it correctly.

It is best to actually use a type when you can. Since it is in an
@Embedded class it is probably treating it as a complex type and
expecting it to be stored as such; then when it is just a Double there
is a problem.

You might call this a bug -- I'm leaning that way; it is a little
confusing for the system to guess how it should load the data when it
is declared as Object and it can do a better job, clearly.

I think in your case using @Property on the "private Object value"
declaration will fix the problem.

I'll create an issue to investigate if we can simplify this and not
require any special hints. At this point unless you mark it as
@Serialized/@Reference everything is embedded.

2010/12/29 Valentín Moreno <vale...@gmail.com>:

Valentín Moreno

unread,
Dec 29, 2010, 11:26:27 AM12/29/10
to mor...@googlegroups.com
Dear Scott:

First of all, I want to thank you for your quick reply.

Solution (@Property) that you proposed works, however I don't understand why..I mean, I guess that if you don't include the annotation Property, Morphia should does the same that without it (of course rename is not allowed in this case). What is the additional functionality of this annotation? 

I am still not understanding why if I use a complex type (MetricResultParameter), I cant use Object as attribute for this complex type. I know the best way to do it is setting a fixed type, however, in my case, flexibility to have different object types on this field is very useful, it avoids me to create different attributes object types with the same finality. I am agree with you when you said I might call it a bug, 

Anyway, thank you very much.
Valentín Moreno.

Scott Hernandez

unread,
Dec 29, 2010, 11:43:14 AM12/29/10
to mor...@googlegroups.com
2010/12/29 Valentín Moreno <vale...@gmail.com>:

> Dear Scott:
> First of all, I want to thank you for your quick reply.

> Solution (@Property) that you proposed works, however I don't understand
> why..I mean, I guess that if you don't include the annotation Property,
> Morphia should does the same that without it (of course rename is not
> allowed in this case). What is the additional functionality of this
> annotation?

This really has to do with the old dichotomy of @Property/@Embedded
from versions of yore.

@Property tells the mapper that the values will be simple like
String/Double/Integer and not a complex (@Embedded) object which is
stored as embedded document in mongodb.

> I am still not understanding why if I use a complex type
> (MetricResultParameter), I cant use Object as attribute for this complex
> type. I know the best way to do it is setting a fixed type, however, in my
> case, flexibility to have different object types on this field is very
> useful, it avoids me to create different attributes object types with the
> same finality. I am agree with you when you said I might call it a bug,
> Anyway, thank you very much.

You can also create multiple classes and use an interface (or base
abstract), but that might be too complicated.

interface MetricResultParameter {}
class MetricResultStringParameter {
String name;
String value;
}

class MetricResultDoubleParameter {
String name;
Double value;

Valentín Moreno

unread,
Dec 29, 2010, 11:54:31 AM12/29/10
to mor...@googlegroups.com
On Wed, Dec 29, 2010 at 5:43 PM, Scott Hernandez <scotthe...@gmail.com> wrote:
2010/12/29 Valentín Moreno <vale...@gmail.com>:
> Dear Scott:
> First of all, I want to thank you for your quick reply.

> Solution (@Property) that you proposed works, however I don't understand
> why..I mean, I guess that if you don't include the annotation Property,
> Morphia should does the same that without it (of course rename is not
> allowed in this case). What is the additional functionality of this
> annotation?

This really has to do with the old dichotomy of @Property/@Embedded
from versions of yore.

@Property tells the mapper that the values will be simple like
String/Double/Integer and not a complex (@Embedded) object which is
stored as embedded document in mongodb.

That's make sense, but I think if you don't include @Embedded/Reference  your attribute must be a simple one (as it occurs if you define a String/Double attribute and you don't need to add the @Property annotation)  this should be the default action. 

If your attribute is embedded or referenced and you don't include the proper annotation is a fault from the coder.

I don't want to bother you more or lengthen the thread, I wanted to give my point of view, in order to see if you are agree or not.

> I am still not understanding why if I use a complex type
> (MetricResultParameter), I cant use Object as attribute for this complex
> type. I know the best way to do it is setting a fixed type, however, in my
> case, flexibility to have different object types on this field is very
> useful, it avoids me to create different attributes object types with the
> same finality. I am agree with you when you said I might call it a bug,
> Anyway, thank you very much.

You can also create multiple classes and use an interface (or base
abstract), but that might be too complicated.

interface MetricResultParameter {}
class MetricResultStringParameter {
String name;
String value;
}

class MetricResultDoubleParameter {
String name;
Double value;
}


Buffff...

Thanks!
Valentín Moreno.

Scott Hernandez

unread,
Dec 29, 2010, 12:19:08 PM12/29/10
to mor...@googlegroups.com
2010/12/29 Valentín Moreno <vale...@gmail.com>:

>
>
> On Wed, Dec 29, 2010 at 5:43 PM, Scott Hernandez <scotthe...@gmail.com>
> wrote:
>>
>> 2010/12/29 Valentín Moreno <vale...@gmail.com>:
>> > Dear Scott:
>> > First of all, I want to thank you for your quick reply.
>>
>> > Solution (@Property) that you proposed works, however I don't understand
>> > why..I mean, I guess that if you don't include the annotation Property,
>> > Morphia should does the same that without it (of course rename is not
>> > allowed in this case). What is the additional functionality of this
>> > annotation?
>>
>> This really has to do with the old dichotomy of @Property/@Embedded
>> from versions of yore.
>>
>> @Property tells the mapper that the values will be simple like
>> String/Double/Integer and not a complex (@Embedded) object which is
>> stored as embedded document in mongodb.
>
> That's make sense, but I think if you don't include @Embedded/Reference
>  your attribute must be a simple one (as it occurs if you define a
> String/Double attribute and you don't need to add the @Property annotation)

In practice that is less likely that an Object is going to be
@Property. But really I think there shouldn't be a need to use
@Property ever; we can find another way to set the name mapping.

>  this should be the default action.
> If your attribute is embedded or referenced and you don't include the proper
> annotation is a fault from the coder.

We have had this discussion before but I feel @Property/@Embedded
should be the default, and it pretty much is now. There are a few
corner cases like Object in an embedded class where it can be a little
confusing what should be done (esp. when load data from mongodb). I'd
like to see it where almost all the annotation are optional, which is
also pretty much true now.

Reply all
Reply to author
Forward
0 new messages