Hi I am persisting a class with a collection(List) of interface.
I see this on link
http://www.datanucleus.org/products/accessplatform_2_1/jdo/orm/embedded.html#Collection
and it says "Embedded elements cannot have inheritance (this may be allowed in the future)"
So, how to persist such objects?
I came accross the same issue a few hours ago, hope it helps others starting with jdo/datanucleus.
As stated in the current docs, the only way to persist a collection of interfaces is through an unidirectional join table. It's not possible to directly embed the objects implementing the interface.
#PersistenceCapable
public class SomeClass {
#Join
#Extension(vendorName="datanucleus", key="implementation-classes", value="ImplementingClass")
private List<SomeInterface> myList;
// this list would be embedded
private List<SomeOtherClass> myOtherList;
// ...
}
#PersistenceCapable
public interface SomeInterface {
// ...
}
#PersistenceCapable
public class ImplementingClass implements SomeInterface {
// ...
}
#PersistenceCapable(embeddedOnly="true")
public class SomeOtherClass {
// ...
}
Related
I have an object model that is handling relations between types. These references sometimes loop back around on themselves, and to stop that (in say a REST call) I am using things like the #JsonIgnore tag to make sure I don't get infinite nest recursion.
The issue with this is more a question of context. If I want an item to be included in one spot but not another (if being nested), #JsonIgnore stops it from both spots.
Example:
public class A implements Serializable{
Set<B> bs;
Set<C> cs;
...
}
public class B implements Serializable{
String name;
Set<D> ds;
...
}
public class C implements Serializable{
B b;
...
}
public class D implements Serializable{
...
}
If A is my main container which is transporting the objects. In the context of B as listed in A, I want the Set<D> to show. When an object B is used in context of C however, I want to hide Set<D> and only show the name.
If I were to mark #JsonIgnore on B.ds it wouldn't show up in either case. Is there some annotation/customization I can put on C.b to ignore inner attributes? #JsonIgnore("ds") or something? Is there another way to handle this entirely?
You can annotate the fields with #JsonView and then specify the serialization view you want to use in particular circumstances. Here's a post about using it with SpringMVC but the approach would be the same regardless.
So in your specific example,
public class View {
interface Full {}
interface Summary {}
}
public class B implements Serializable{
#JsonView({View.Summary,View.Full})
String name;
#JsonView(View.Full)
Set<D> ds;
}
I've got around 5 objects that I want to do similar things with.
I figured out that not to polute the code I will put a logic for those objects in one place.
public class MetaObjectController<T extends MetaObject> {
#Autowired
private final MetaObjectRepository<T> repository;
// generic logic
Here's how repository looks:
public interface MetaObjectRepository<T extends MetaObject> extends GraphRepository<T> {
T findByName(String name);
}
Now, I create concrete class which uses delegation:
public class ExperimentalController {
#Autowired
private final MetaObjectController<MetaCategory> metaController;
#RequestMapping(method = RequestMethod.POST)
public void add(#RequestBody MetaCategory toAdd) {
metaController.add(toAdd);
}
Now, when I look at the generated queries I see, that although instantiated correctly, repository puts MetaObject as an entity name instead of runtime type.
Is there a way to force the repository to use runtime type?
Please don't advise to put a #Query annnotation. That's not what I am looking for.
This is most probably due to type erasure: at runtime there is only the type constraint available which is MetaObject. If you want to use (via spring-data) the actually relevant subclass you will have to create explicit interfaces of the MetaObjectRepository like this:
public class Transmogrifier extends MetaObject
public interface MetaTransmogrifierRepository
extends MetaObjectRepository<Transmogrifier> {}
I'm using datanucleus 3.2.5 / JDO for persisting objects to a MongoDB database.
While trying to persist one map of lists I'm getting the following exception:
RuntimeException: json can't serialize type [list element type here]
Some sample code:
#PersistenceCapable
public class SomeClass {
private Map<String, List<SomeOtherClass>> myAttribute;
// ...
}
#PersistenceCapable(embeddedOnly="true")
public class SomeOtherClass {
private String attribute;
// ...
}
I could get around this problem annotating the embedded attribute as #Serialized, but I would rather prefer a more elegant way.
Am I missing anything? Is there a better approach to this issue?
Quoting Andy's reply to my question in the DataNucleus forums:
No persistence spec defines any support for a container of a container. You are always recommended to make the inner container (List in your case) a field of an intermediate class.
So there are two approaches here:
Use an intermediate class
By far the most elegant and maintainable solution. Following the example toy code:
#PersistenceCapable
public class SomeClass {
private Map<String, SomeOtherClassContainer> myAttribute;
// ...
}
#PersistenceCapable(embeddedOnly="true")
public class SomeClassContainer {
private List<SomeOtherClass> myAttribute;
// ...
}
#PersistenceCapable(embeddedOnly="true")
public class SomeOtherClass {
private String attribute;
// ...
}
Mark the attribute as #Serializable
Ugly and probably a source of headaches, specially if relying on java default serialization.
#PersistenceCapable
public class SomeClass {
#Serializable
private Map<String, List<SomeOtherClass>> myAttribute;
// ...
}
#PersistenceCapable(embeddedOnly="true")
public class SomeOtherClass implements Serializable {
private String attribute;
// ...
}
I'm wondering how an abstract class with generics would handle with JPA? I mean what kind of annotations do I need for the field?
Consider these:
#MappedSuperclass
public abstract class AbstractMyClass<T> {
// What about Strings and Integers? Do I need some kind of #LOB?
private T field;
public T getField() {
return field;
}
public void setField(T field) {
this.field = field;
}
}
And then these
#Entity
#Table(name = "String")
public class MyStringClass extends AbstractMyClass<String> {
}
#Entity
#Table(name = "Integer")
public class MyIntegerClass extends AbstractMyClass<Integer> {
}
JPA is perfectly able to handle your proposed, because the generic appears at the abstract class level and for your concrete classes it has exactly a single value per class. In fact, JPA will store your subclasses in one or more table, according to the #InheritanceStrategy you have chosen and uses different mechanism for that.
You can figure out yourself why your case is not a problem, reasoning about how an ORM could save the two classes on a DB:
You can store MyStringClass and MyIntegerClass in the same table, adding a Discriminator column so that the ORM, when it loads from the DB, know which constructor should be called.
You can store every subclass in more table.
What is not possible, on the other side, is to define a generic
#Entity
#Table(name = "MyGenericClass")
public class MyGenericClass<T> {
private T t;
public MyGenericClass(T t) {
this.t=t;
}
}
The reason for this is that, at compile time, the T is "erased" because of type erasure. It is used at compile time to verify signatures and correctness of types, but then it is turned into a java.lang.Object inside the JVM. If you follow until now, you should be able to understand the following:
In your case, every concrete subclass of AbstractMyClass has a type T which is defined for all instances of the class. While the T information is not retained into the AbstractMyClass, it is retained and unique inside the subclasses.
In the second case I posted, each possible concrete instance of MyGenericClass could have a possible different value for T, and because of type erasure this information is not retained.
*Note: the fact that the second case cannot be handled by JPA is absolutely reasonable and if you fall in that case you should ask yourself questions about your design. Generics are a great tool to design flexible classes which can handle other classes in a type-safe manner, but type-safe is a programming language concept which has nothing to do with persistance.
Extra : you could use javap to see what really is erasure. Take off annotations from MyGenericClass and compile it.
G:\>javac MyGenericClass.java
G:\>javap -p MyGenericClass
Compiled from "MyGenericClass.java"
public class MyGenericClass extends java.lang.Object{
private java.lang.Object t;
public MyGenericClass(java.lang.Object);
}
We can. if the T implements Serializable
#Entity
public class IgsSubject extends BasicObject implements Serializable{
private static final long serialVersionUID = -5387429446192609471L;
#MappedSuperclass
public class IgsBasicLog<T> extends BasicObject {
#ManyToOne
#JoinColumn(name = "ITEM_ID")
private T item;
#Entity
public class IgsLogA extends IgsBasicLog<IgsSubject> implements Serializable {
private static final long serialVersionUID = -8207430344929724212L;
}
Using Hibernate 3.6.8.Final and Spring 3.0.5.RELEASE , I'm trying to add some Common DAO functionality for classes that have multiple implementations overridden higher up to implement the specific classes however it doesn't work for DetachedCriteria.
Example:
In base class:
public interface ICat {
public void setMeowSound(String meow);
public String getMeowSound();
}
Then each inherited project would define the hibernate annotations.
e.g.
#Entity
#Table(name="SQUAWKY_CATS")
public class SquawkyMeowingCat implements ICat, Serializable {
#Id
#Column(name="SQUAWK_NAME")
private String meow;
public String getMeowSound() {
return meow;
}
public void setMeowString(String meow) {
this.meow = meow;
}
}
This means I can use:
Criteria criteria = Session.createCriteria(ICat.class);
And Spring/Hibernate knows that it pulls the annotations for ICat from the concrete inheritance in the particular project.
However if I try to do:
DetachedCriteria subQuery = DetachedCriteria.forClass(ICat.class,"inner"); // etcetera
then I get an Unknown entity at runtime for ICat.
Now this makes sense as in the first instance is creating it off the Session so it has all the configuration that it needs whereas the DetachedCriteria is a static method however it errors when trying to do the
criteria.list()
by which time it has picked up the Session and should know that ICat is actually a SquawkyMeowingCat which has all the annotations.
So my questions are two part:
1) Is this known behaviour and will be like this forever more?
2) Can anyone think of a simple way around it without using an Interface and concrete ClassHolder which hands back the instance of the class it needs to create?
I'm not sure about the case of the DetachedCriteria, but one way to avoid explicit dependence on the concrete class might be to query Hibernate's metadata using the interface:
public <T> Class<? extends T> findEntityClassForEntityInterface(
SessionFactory sessionFactory,
Class<T> entityInterface
) {
for (ClassMetadata metadata : sessionFactory.getAllClassMetadata().values()) {
Class entityClass = metadata.getMappedClass(EntityMode.POJO);
if (entityInterface.isAssignableFrom(entityClass)) {
return entityClass;
}
}
return null;
}
With the usual caveats about the robustness of illustrative code spippets.