Mapstruct inherit #Mappings - java

Trying to make a MapStruct implementation where I have a "parent"-object like this:
public abstract class Parent {
private String id;
}
Then I have children with a whole bunch of more attributes such as:
public class ChildA extends Parent{
private String name;
//And so on...
}
public class ChildB extends Parent{
private String address;
//And so on...
}
How do I represent this data-structure in MapStruct mappers? I only want to map the children and not the parent. I have successfully made a mapper to map a child with an abstract class, but I can't get the "parent" mapping to tag along without explicitly stating it inside the child-mappers.
Is there a way I can do something like:
#Mapping(source = "id" target = "targetId")
In a parent mapper, and then inherit that mapping statement to the children? I don't want the parent to have a mapper on its own, I just want it to hold that mapping statement to reduce redundancy.
I would love to extend my abstract child-mapper class with a parent class and then simply inherit. Is this possible?

Related

Deserialising Jackson abstract and multiple concrete classes

I am working in Java with Jackson.
I have an abstract class Base.class, which looks as follows:
#JsonDeserialize(as = Child1.class)
public abstract class Base {
#JsonProperty("field1")
private Boolean field1;
#JsonProperty("field2")
private Long field2;
//getters, setters
}
And a bunch of child classes that extend the abstract class, that look like this:
public class Child1 extends Base {
#JsonProperty("field3")
private Boolean field3;
#JsonProperty("field4")
private Long field4;
//getters, setters
}
When I deserialise the following JSON, it works perfectly well:
Base base = mapper.readValue(new File("src/test/resources/testerTemplate/example.json"), Base.class)
example.json :
{
"field1":true,
"field2":123456,
"field3":false,
"field4":123456,
}
The issue is that this limits this structure to one-to-one relationship between base and child classes - to deserialise into other child classes I would need to change the annotation every single time. I have tried other annotations but has not been able to work it out. How do I do this?
I have worked out a solution that allows the code to do what I need it to do, although I am not entirely happy with the outcome. Nonetheless, it works.
The solution is to extend the Base.class by an intermediate abstract class that will be deserialized instead of the Base.class, like so:
Base.class (contains the generic fields we want to include when deserialising child classes):
public abstract class Base {
#JsonProperty("field1")
private Boolean field1;
#JsonProperty("field2")
private Long field2;
//getters, setters
}
An "extension" class that we will use to deserialize a specific child:
#JsonDeserialize(as = Child1.class)
public abstract class BaseChild1 extends Base {}
And the Child1.class:
public class Child1 extends BaseChild1 {
#JsonProperty("field3")
private Boolean field3;
#JsonProperty("field4")
private Long field4;
//getters, setters
}
This means that for every child class, we would create an empty abstract class that extends from the Base.class.
We then deserialize as follows:
ObjectMapper mapper = new ObjectMapper();
BaseChild1 child1 = mapper.readValue(new File("src/test/resources/testerTemplate/example.json"), BaseChild1.class)
BaseChild2 child2 = mapper.readValue(new File("src/test/resources/testerTemplate/example.json"), BaseChild2.class)
...
It is not perfect, but it works.

What is the best way to persist a hierarchy with an abstract class w/o a table

I have a simple inheritance model:
public abstract class Base {
int id;
string name;
}
public class Derived1 extends Base {
int valueD1;
}
public class Derived2 extends Base {
int valueD2;
}
How should I map the classes (with JPA annotations) so that I have separate tables for Derived1 and Derived2 (Table per concrete class), and no table for Base.
Should I use #MappedSuperclass, or #Embeddable (and skip inheritance), or #Inheritance?
Use #MappedSuperclass, and define distinct tables for each entity, IMHO,
But it depends on if you will most likely query for the parent class or if you use both derived entities for themselves, without having the need to query two tables.

JPA- override identity attribute in mapped super class?

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

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.

Create index on field from parent class

I have problem with adding index. I use hibernate with annotation driven configuration.
I have something like this:
#MappedSuperclass
public abstract class BaseEntity {
#Id
private String id;
private String profileId;
...
//getters and setters
}
and several child classes
#Table(name="note")
public abstract class Note extends BaseEntity{
//different fields
}
#Table(name="message")
public abstract class Message extends BaseEntity{
//different fields
}
I want to add index to field "profileId" in class BaseEntity. But if I do so, with annotation #Index(name="profileid_index"), it creates only for table "note", and fails on "message", because index "profileid_index" already exist.
I did not find way, how to make hibernate generate unique index names. Or may be someone knows another solution how to index field in parent class.
Did you have a look on #Tables annotation: http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html_single/ ?
You can do stuff like:
#Tables(value={#Table(appliesTo="table1", indexes={#Index(name="index1", columnNames={"column1", "column2"})}),
#Table(appliesTo="table2", indexes={#Index(name="index1", columnNames={"column1", "column2"})})})
Should help in your case if you put this annotation to your #MappedSuperclass, although I don't know if there is a more cleaner solution
Being more precise, you could try for your case:
#Tables(value={#Table(appliesTo="note", indexes={#Index(name="index_profile_id1", columnNames={"profileId"})}),
#Table(appliesTo="message", indexes={#Index(name="index_profile_id2", columnNames={"profileId"})})})

Categories