Overriding #JsonProperty in a subclass with #JsonIgnore - java

I have a parent class
public class Parent {
#JsonProperty("ID")
private int id;
// getter and setter
}
and a corresponding subclass
public class Child extends Parent {
#Override
#JsonIgnore
public int getId() {
return id;
}
}
While the field id should be serialized for Parent and other subclasses, I do not want to include it in the specific subclass Child. However, the annotation #JsonIgnore doesn't override the annotation #JsonProperty and the id is also included when serializing the Child.
Interestingly, it works with #JsonIgnoreProperties("ID") at class level of Child, but I would like to know how it can be accomplished at method level and why my approach doesn't work.
I am using Jackson in version 2.9.6.

Related

JPA how to annotate generic entity field conditionally?

I have this generic entity:
#MappedSuperclass
abstract class Position<T> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Enumerated(EnumType.STRING)
private T name;
}
But there's a case where the generic type is a String:
#Entity
class ChildPosition0 extends Position<String> {
}
And, JPA will complaint that String is not an enum in this case, but I need to annotate this name field if it's an enum, if not, the database will mark it as int type, and that's not ideal. How do I solve this? How to annotate the field conditionally?
My workaround:
Use Position as a parent class, and adding those field in child class individually, even though they share the same field:
#MappedSuperclass
abstract class Position {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
}
And extends it from child entity like this:
Child1:
#Entity
public class ChildPosition1 extends Position {
#Enumerated(EnumType.STRING)
private Priority name; // <- Priority is enum type
}
Child2:
#Entity
public class ChildPosition2 extends Position {
private String name;
}
This is too ugly IMO. And Java does not allow class field override from child class. So, back to the question: how to annotate generic field conditionally?

Objectbox inherit properties from base class (which is NOT an entity itself)

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;
}
}

Protected member Vs private member in inheritance java

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);
}
}

Inheritance with JAXB (unmarshalling)

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.

Applying annotations to fields inherited from #MappedSuperclass

Has:
#MappedSuperclass
class Superclass {
#Id
#Column(name = "id")
protected long id;
#Column(name="field")
private long field;
}
and
#Entity
class Subclass extends Superclass {
}
How to annotate inherited id with #GeneratedValue and field with #Index within Subclass?
How to annotate inherited id with #GeneratedValue and field with #Index within Subclass?
AFAIK, you can't. What you can do is overriding attributes and associations (i.e. change the column or join column) using the AttributeOverride and AssociationOverride annotations. But you can't do exactly what you're asking.
For the GeneratedValue, consider using XML mapping to override the strategy if you don't want to declare it in the mapped superclass.
For the Index (which is not a standard annotation by the way), did you actually try to declare it at the table level using Hibernate's Table annotation instead (I'm assuming you're using Hibernate)?
#Table(appliesTo="tableName", indexes = { #Index(name="index1", columnNames=
{"column1", "column2"} ) } )
creates the defined indexes on the
columns of table tableName.
References
JPA 1.0 Specification
Section 2.1.9.2 "Mapped Superclasses"
Section 9.1.10 "AttributeOverride Annotation"
Section 9.1.11 "AttributeOverrides Annotation"
Section 9.1.12 "AssociationOverride Annotation"
Section 9.1.13 "AssociationOverrides Annotation"
Hibernate Annotations Reference Guide
2.4. Hibernate Annotation Extensions
Chapter 3. Overriding metadata through XML
As for #GeneratedValue, it is possible to do like this:
#MappedSuperclass
class Superclass {
#Id
#Column(name = "id")
#GeneratedValue(generator = "id_generator")
protected long id;
#Column(name = "field")
private long field;
}
#Entity
#SequenceGenerator(name = "id_generator", sequenceName = "id_seq")
class Subclass extends Superclass {
}
You might be able to do this if you apply the annotations to the accessor methods instead. (I haven't tried this, so I can't guarantee that it'll work.)
#MappedSuperclass
public class Superclass {
#Id
#Column(name = "id")
public long getId() {
return id;
}
.
#Entity
public class Subclass extends Superclass {
#GeneratedValue
public long getId() {
return super.getId();
}
Just in case anyone else searches for this, I used the following code which adds in some overhead, but for processing Field annotations only shouldn't add that much:
private List<Field> getAllFields() {
List<Field> fieldList = new ArrayList<Field>();
// Add all fields from the current class
fieldList.addAll(Arrays.asList(mElement.getClass().getDeclaredFields()));
// Use an index to iterate over mElement's parent types
Class clazz = mElement.getClass();
// Get any fields from the parent class(es)
while (clazz.getSuperclass() != null) {
fieldList.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));
// Set it to that parent class
clazz = clazz.getSuperclass();
}
return fieldList;
}
The returned list would contain all fields for all parent and child classes with mElement being the object you are searching for annotations from. Hope this helps.

Categories