I'm trying to use greenDAO's implementsInterface method, here is most of my main generator class:
private static void addTables(final Schema schema) {
Entity photo_pronoun = addCard(schema);
Entity simple_pronoun = addSimpleCard(schema);
Entity original_pronoun = addOriginalCard(schema);
//implementsInterface method
original_pronoun.implementsInterface("addNewCard");
simple_pronoun.implementsInterface("addNewCard");
}
private static Entity addCard(final Schema schema) {
Entity card = schema.addEntity("addNewCard");
card.addIdProperty().primaryKey().autoincrement();
card.addStringProperty("cardName").notNull();
card.addStringProperty("cardSpeech");
card.addByteArrayProperty("cardIcon");
return card;
}
private static Entity addSimpleCard(final Schema schema) {
Entity card = schema.addEntity("addSimpleCard");
card.addIdProperty().primaryKey().autoincrement();
card.addStringProperty("cardName").notNull();
card.addStringProperty("cardSpeech");
card.addByteArrayProperty("cardIcon");
return card;
}
private static Entity addOriginalCard(final Schema schema) {
Entity card = schema.addEntity("addOriginalCard");
card.addIdProperty().primaryKey().autoincrement();
card.addStringProperty("cardName").notNull();
card.addStringProperty("cardSpeech");
card.addByteArrayProperty("cardIcon");
return card;
}
When I run this to create my files I get an error in original_pronoun and in simple_pronoun on my first line at addNewCard:
interface expected here
public class addOriginalCard implements addNewCard {
I get that error because its not an interface, but I'm confused on how to fix it. The implementsInterface method says it takes a string but I've tried this and the database name with no joy. Can anyone tell me what I need to do here?
This is not a greenDAO problem: addNewCard is a class, not an interface. If your model class needs to inherit from another class, you have to use setSuperclass() method. Example:
original_pronoun.setSuperclass("addNewCard");
Note that greenDAO doesn't support another entity as a super class yet, if this is your intention.
Check greenDAO docs for Inheritance and Interfaces.
See also this question: Implements vs. Extends. When to use? What's the Difference?
Related
I'm creating a framework for spring-data-elasticsearch as a practice project.
My question is about the #Document tag that will create the index based on the name provided in indexName parameter of annotation.
However, I'm thinking is it possible to make it dynamic! In most of my usecases, the index name will match the class name. All my index classes will extend a abstract class which has generic implementation for all the and specific implementations needs to be done in the entity class.
This means, I have to maintain the #Document annotation for every entity. But since all the entities will extend a particular abstract class, is it possible to annotate the abstract class and somehow tell spring to use the class name as index name.
import org.springframework.data.elasticsearch.annotations.Document;
#Document(indexName = "BaseClassName OR something like Animal.getName" /*And other index properties of-course*/)
abstract class Animal {
String name;
public String getName() {
return name;
}
public abstract String makeSomeNoise();
}
All the concrete class that extends the Animals will be indexed in Elasticserch.
abstract class TwoLeggedAnimals extends Animal {}
abstract class FourLeggedAnimals extends Animal {}
The above two are just the grouping classes. For the sake of the example
class Duck extends TwoLeggedAnimals {
public Duck() {
this.name = Duck.class.getSimpleName();
}
#Override
public String makeSomeNoise() {
return "quack";
}
}
Class Duck extends TwoLeggedAnimals which in turn extends the "Animals" class and thus, Duck qualifies for index creation.
The same explanation for Horse class
class Horse extends FourLeggedAnimals {
Horse() {
this.name = Horse.class.getSimpleName();
}
#Override
public String makeSomeNoise() {
return "neigh";
}
}
You did not write what your specific problem or error is and what ES version you are using.
You can put the #Document annotation with the index name on an abstract baseclass and then use a derived class to store your entites into the index without adding some annotation on your derived class; this works with no problems.
But you cannot store different types (like TwoLeggedAnimals and FourLeggedAnimals) in the same index since Elasticsearch 6.0 (see ES 6.0 breaking changes). Your program will work as long as you are using one type, as soon as you try to store the second type, you will get
Elasticsearch exception [type=illegal_argument_exception, reason=Rejecting mapping update to [animals] as the final mapping would have more than 1 type: [twoleggedanimal, fourleggedanimal]]
The last 5.x version 5.6 had support until 2019-03-11 (Elastic end of life dates), so that's not supported anymore.
So, as it is not possible to store more than one type in an index, you will have to rethink your classes and how you store them - please check ES removal of types as well, if the alternatives outlined there might help you.
I have an abstract base class with existing subclasses that is mostly used for defining a number of common fields and associated methods. I have a separate concrete class that "organically evolved" (i.e., bad design due to unforeseen feature requests) to end up with all the same fields defined in that abstract subclass.
Is there any way of having that separate class extend the abstract class and carry over the data of existing stored instances of that separate class? I would like to use InheritanceType.SINGLE_TABLE, but if another strategy makes it easier or possible, I guess that's fine too.
Also, those are entities referenced in other entities (OneToMany). Is that a problem? Hibernate uses only one global sequence for assigning entity ids - so it should in theory be possible to not break those references even if the data is moved to another table, right?
Already tried a few things, but no luck so far (e.g., add the "extend" to the separate class, hard-code it to use the same table as the base class, manually add a field for the discriminator...).
I am also happy about any pointers to examples/docs on how to carry out class hierarchy changes and other data model changes with JPA/Hibernate without losing data!
So, here's a simplified example of the situation. Base is the abstract base class that already has sub-classes.
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#Table(name = "Base")
public abstract class Base {
private long persistenceId;
private String privateField;
#Id
#GeneratedValue
public long getPersistenceId() {
return persistenceId;
}
public void setPersistenceId(long persistenceId) {
this.persistenceId = persistenceId;
}
[...]
}
#Entity
public class SubclassToBe {
private long persistenceId;
private String privateField;
private String someFieldNotInBaseClass;
#Override
#Id
#GeneratedValue
public long getPersistenceId() {
return persistenceId;
}
#Override
public void setPersistenceId(long persistenceId) {
this.persistenceId = persistenceId;
}
[...]
}
The goal would be to have SubclassToBe inherit from Base, removing the definitions of shared fields but keeping the information stored there. And at the same time, not break references to the persistence ids of SubclassToBe objects that are used in other objects as part of OneToMany relations.
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 {
// ...
}
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.
I'm working on GAE-based applications, which uses JDO to access datastore. I need to implement polymorphic relationship between persisted objects.
There's abstract parent class:
#PersistenceCapable
#Inheritance(strategy = InheritanceStrategy.SUBCLASS_TABLE)
public abstract class Parent {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
#Extension(vendorName = "datanucleus", key = "gae.encoded-pk", value = "true")
String id;
// ....
And several child classes:
#PersistenceCapable (identityType = IdentityType.APPLICATION)
public class Child extends Parent {
// ....
Also, there's one more class, which should have reference to one of child classes. According to "Polymorphic Relationships" section of "Entity Relationships in JDO" article, the best way to implement such relationship is to store key of an object, so this class looks in the following way:
#PersistenceCapable (identityType = IdentityType.APPLICATION)
public class OtherClass {
#Persistent
private String reference;
// ....
I retrieve string key of referenced object from instance of OtherClass. Then I would like to obtain referenced object itself: it's an instance of one of Parent subclasses. BUT:
If I do it with pm.getObjectById(oid) method:
Object object = pm.getObjectById(reference);
JDOObjectNotFoundException exception is thrown (javax.jdo.JDOObjectNotFoundException: No such object FailedObject:...).
If I do it with getObjectById(class, key) method:
Parent object = pm.getObjectById(Parent.class, reference);
FatalNucleusUserException exception is thrown (org.datanucleus.store.appengine.FatalNucleusUserException: Received a request to find an object of kind Parent but the provided identifier is the String representation of a Key for kind Child)
What is correct way to retrieve instance of one of subclasses referenced in another entity?
UPDATE: I found this thread in GAE google group, but frankly it did not help me a lot.
I found the same problem with JDO and App Engine, so I started a project that implements a workaround for this. https://code.google.com/p/datanucleus-appengine-patch/
My first test with the code I have now looks okay, feel free to try it out at give me some feedback.
Actually my workaround may solve your problem 2 ways.
I implemented a getObjectById(class, id) that also looks for kinds that are instances of the provided class.
I implemented a getObjectById(oid) that does some special handling of lookup if oid is of type com.google.appengine.api.datastore.Key, then it will figure out the correct class to return.
I added a new annotation #PolymorphicRelationship that will make is easy to handle to workaround that App Engine describes, with storing the keys. Sample shown below:
#Persist
public Collection<Key> myChildKeys;
#NotPersistent
#PolymorphicRelationship(keyField ="myChildKeys")
public Collection<TestChild> myChildren;
I'm using this rather cancerous and smelly anti-pattern to get around this limitation of JDO/App Engine.
#JsonIgnore
#Persistent(mappedBy="account")
private List<XProvider> xProviders;
#JsonIgnore
#Persistent(mappedBy="account")
private List<YProvider> yProviders;
// TODO: add extra providers here and in getProviders() below...
And then to get the collection:
public List<XProvider> getXProviders() {
if (xProviders == null) {
xProviders = new ArrayList<XProvider>();
}
return xProviders;
}
//etc with other getters and setters for each collection.
public List<Provider> getProviders() {
List<Provider> allProviders = new ArrayList<Provider>();
// TODO: add extra providers here...
allProviders.addAll(getXProviders());
allProviders.addAll(getYProviders());
return allProviders;
}
It's a bad solution, but any port in a storm...
(Also relates a little to this bug, using interfaces as the collection type http://code.google.com/p/datanucleus-appengine/issues/detail?id=207)
App Engine's JDO layer doesn't currently support polymorphism. In fact, I'm not sure if JDO supports it in general or not.