I have an abstract class Entity and then multiple instance can extend Entity
like
A extends Entity {
}
B extends Entity {
}
Now all the entity needs to have entityId
So should I have entityId as a private field in Entity and set it via the constructor, or as a protected member in Entity, so that the subclasses can access it directly?
First off, you can rename entityId as id as it is obviously the id of the entity. It is a member of Entity.
I will assume that id cannot be changed and as such it should be private, set only once and only in the constructor. The class should have a public getId() method. This way other objects can access it in addition to subclasses.
With this implementation id can't be changed accidentally by subclasses.
You should have entityId as part of entity base type as protected.
From a design perspective, entityID should be part of the entity. So, place it in Entity class and make it protected so that its subclasses can access it.
Use protected, So that all the inherited classes can access it.
If the base class constrctor accepts value for entity id, like follows
class Entity
{
protected int EntityId;
public Entity(int _entityId)
{
EntityId=_entityId;
}
}
Then you can use "super" function to call base class constructor from derived class constructor
class ExtendedEntity extends Entity
{
public ExtendedEntity (int _entityId)
{
super(_entityId); // calling base class constructor
}
}
This is probably the main reason why protected members exist. Basically it's the same as private but with the exception that it appears public to your subclasses and to classes in the same package (if that's a concern, go with private).
Now, that's the general theory for instance variables in an inheritance structure, but as others have pointed out, as this seems to be about an ID field, it's still better to make it private and maybe also final. Then write a public getter method, except if no one should be able to get the ID except from the subclasses, then make it protected.
Make it a private field in Entity and make (protected) accessors (getter/setter) so that subclasses have access to the field via the setter or getter (basic OO principles)
You can also write a specific constructor for the Entity class, taking an id as argument and call this constructor from the extending classes. By doing so, your subclasses are always forced to set an id.
Eg.
public class Entity {
private int id;
public Entity(int id) {
setId(id);
}
protected int getId() {
return id;
}
protected void setId(int id) {
this.id = id;
}
}
public class A extends Entity {
public A(int id) {
super(id);
}
}
Related
I have a simple base class in which I want to have some common fields, like id etc. The base class is not an Entity by itself.
public class Base {
#Id
protected long id;
protected String someOtherCommonProperty;
}
And I have an entity class, extending the base class.
#Entity
public class Entity extends Base {
String name;
String address;
}
I would expect the entity class to inherit the fields from the base class, but what I get is
[ObjectBox] No #Id property found for 'Entity', add #Id on a not-null long property.
Is there any way to fix that, besides using interfaces and have a lot of duplicated code?
You can use the #BaseEntity annotation.
Have a look at the documentation: Objectbox - Entity Inheritence.
Shameless copy for future reference:
In addition to the #Entity annotation, we introduced a #BaseEntity annotation for base classes, which can be used instead of #Entity.
There three types of base classes, which are defined via annotations:
No annotation: The base class and its properties are not considered for persistence.
#BaseEntity: Properties are considered for persistence in sub classes, but the base class itself cannot be persisted.
#Entity: Properties are considered for persistence in sub classes, and the base class itself is a normally persisted entity.
Example:
// base class:
#BaseEntity
public abstract class Base {
#Id long id;
String baseString;
public Base() {
}
public Base(long id, String baseString) {
this.id = id;
this.baseString = baseString;
}
}
// sub class:
#Entity
public class Sub extends Base {
String subString;
public Sub() {
}
public Sub(long id, String baseString, String subString) {
super(id, baseString);
this.subString = subString;
}
}
I have an abstract class annotated as #MappedSuperclass. This class defines attributes common to all JPA classes such as Id.
I would like to override Id attribute mapping defined in the abstract super class and assign a sequence generator. Is it possible to override Id attribute mapping and assign a different sequence generator in JPA 2.x?
One thing that pops into my head is to use two base classes; one without the ID property and one that explicitly adds the ID property. Then you have freedom if you extend the one with ID or the one without ID so you can provide one specifically in the entity. Code skeleton without annotations:
public abstract class _Base {
// common properties here
}
public abstract class _BaseWithId extends _Base {
private Long id;
}
public class MyEntity1 extends _BaseWithId {
}
public class MyEntity2 extends _Base {
private Long id;
}
I have many entities with common properties. There is no xml schema, so I write jaxb entities on my own.
abstract class SuperEntity {
protected String id;
protected String name;
#XmlElement
public void setId() { .. sets Id .. }
#XmlElement
public void setName() { .. sets name .. }
}
// id and name are null after deserialization .. they are completely ignored
// there are other entities such as this, I don't want to repeat my code
#XmlRootElement
#XmlSeeAlso({SuperEntity.class})
class SpecificEntity extends SuperEntity {
protected String specificField;
#XmlElement
public void setSpecificField() { .. sets specific field .. }
}
SuperEntity is not deserialized (unmarshelled) at all, leaving fields null. If i copy fields and setters from superclass to specific class, it works, but I dont want to just copy that code to every child entity. Thank you for your help.
Change the class definitions to
#XmlRootElement
#XmlSeeAlso({SpecificEntity.class})
abstract class SuperEntity {
#XmlRootElement
class SpecificEntity extends SuperEntity {
When JAXB is processing a class model it will also process super classes (the ones not annotated with #XmlTransient). By default it won't process subclasses. The #XmlSeeAlso needs to go on the super class and reference the subclasses.
I am trying to use an inner class as embeddable to represent some complicated properties of the outer class. When I store this, there is no information from the inner class in the database schema generated by eclipselink.
Does what I'm trying to do seem like a good idea? Why doesn't eclipselink seem to recognize them #Basic attribute on the getRate() in Attributes?
Some other info: Measure must be instantiated using a factory which is provided to the constructor of Person, so I don't even know how I'm going to be able to use this at all. It seems more and more likely that I'll have to make a separate class just to store the state of Person in simple terms (like doubles, not Measures) and use those to create the real Person-type objects, but that has very sad implications for the rest of my application.
#Entity
public static class Person {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Transient
public Measure<Double, CleanupRate> rate;
#Embedded
private Attributes attributes;
#Embeddable
public static class Attributes {
#Transient
private Person person;
public Attributes() {
}
public Attributes(Person person) {
this.person = person;
}
#Basic
public double getRate() {
return person.rate.getInternalValue();
}
public void setRate(double value) {
person.rate.setInternalValue(value);
}
}
public Person() {
rate = udm.getMeasureFactory().createMeasure(0.0, CleanupRate.class);
attributes = new Attributes(this);
}
public void setRate(double rate) {
this.rate.setValue(rate);
}
}
Edit:
In order to inject the measure dependency into my objects when they are retrieved from storage, I've added an interface which injects the dependency and used it in my DAO. Since the DAO can be injected, I can propagate the dependency down to the retrieved objects. I got the idea from a blog.
private <T extends UomInjectable> List<T> //
getListOfUomInjectableType(final Class<T> klass) {
List<T> result = getListOfType(klass);
for (UomInjectable injectable : result) {
injectable.injectUomFactory(udm);
}
return result;
}
It is using the access type from the Person class, which is set to field, and so not seeing the annotation at the property level.
You will need to change the access type using Access(PROPERTY) on the embeddable class, and should remove the #Transient annotation on the person attribute.
I think in general you're going to be in trouble having Entities (Embeddable or otherwise) that need constructors with arguments. I'm not sure how that might be related to your schema generation issue, but I think this will be a problem trying to persist/retrieve these objects.
As you hinted, JPA requires all entity types to have a no-argument constructor. While your Attributes class has one, it leaves the 'person' field as null which will fairly quickly result in NPE's. Same with the Person constructor (maybe you left out the one that passes in 'udm' from the sample code?).
The set the Person for the Attributes, just use property access in Person and set it in your setAttributes method.
See,
http://en.wikibooks.org/wiki/Java_Persistence/Embeddables#Relationships
I have two classes. One is the entity class, the other serves as a composite key class.
The code is as followed.
#Entity
public class Supply {
#Embeddable
class Id implements Serializable {
#Column(name = "supplier_id")
private long supplierId;
#Column(name = "merchandise_id")
private long merchandiseId;
public Id() {
}
public Id(long sId, long mId) {
this.supplierId = sId;
this.merchandiseId = mId;
}
}
#EmbeddedId
private Id id = new Id();
}
If I use try to find
from Supply where merchandise_id=%d and supplier_id=%d
Hibernate will throw an exception,namely:
No default constructor for entity: com.entity.Supply$Id; nested exception is org.hibernate.InstantiationException: No default constructor for entity: com.entity.Supply$Id
However, I found that if I change class Id to static. Everything will be fine.
I am just curious about how all these stuff can happen.
If the class is not static, it requires an instance of the outer class in order to be instantiated - so there will be no default constructor. You'd have to use syntax similar to:
new Supply().new Id();
If the Id class is static, you can just call:
new Id();
I always add an empty protected constructor to the class to solve this issue like so:
protected Classname(){}
In your case it would look like this:
protected Id(){}
If class is non static it will require outer class instance to exist. So, I think, generated constructor in this case will have implicit parameter for outer class.
Update
As I expected:
$ javap -classpath . Supply\$Id
Compiled from "Supply.java"
class Supply$Id extends java.lang.Object{
final Supply this$0;
Supply$Id(Supply);
}