Lets assume we have the following situation:
We want to inherit all the values of the class Articles except one it's name for instance. How can we achieve it? I know that if we want to inherit everything from the Articles just write
public class Fruits extends Articles{ ... }
but how can we manage to inherit only specific attributes of the class Articles, ie. every attribute except one and one attribute leave intact?
EDIT:
#Entity
#Table(name = "Article")
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Article {
#Id #GeneratedValue(strategy=GenerationType.AUTO)
#Basic(optional = false)
#Column(name = "ART_ID")
private Long id;
#Basic(optional = false)
#Column(name = "ART_NAME")
private String name;
#Basic(optional = true)
#Column(name = "ART_COST")
private String cost;
// ...
}
#Entity
#Table(name="Fruits")
#AttributeOverrides({
#AttributeOverride(name="name", column=#Column(name="ART_NAME")),
#AttributeOverride(name="cost", column=#Column(name="ART_COST")),
})
// This is what is causing the issue. Fruits inherits something which is already defined in it's scope, and as the result can't declare exactly how to process it.
public class Fruits extends Article {
#Id #GeneratedValue(strategy=GenerationType.AUTO)
#Basic(optional = false)
#Column(name = "FRU_ID")
private Long fruitID;
#Column(name="FRU_FROZEN")
private String fruFrozen;
//...
}
So, I think code won't work, because this will result in multiple IDs in the entity hierarchy, so is there any other way I can solve this?
You can't remove a member from Articles
When name is a member of Articles and Fruits IS A Articles,
there could not be a way to remove name
You may hide some members from Articles using scope private
An other approach is to create a class "BaseArticles" without the member name.
Then derive both Articles AND Fruits from BaseArticles
public BaseArticles {
// HAS NO private String name;
...
}
public Article extends BaseArticles {
private String name;
...
}
public Fruits extends BaseArticles {
// WITHOUT private String name;
...
}
However, it is not simple but possible to deal with OO-inheritance using hibernate.
There is an annotation but I do not know off hands
You can put base class not required attribute as a private.
Related
I'm working with Spring Data JPA and I'm trying to create 4 different entities that will have exactly the same fields but they will be stored in 4 different tables.
This is my key class
public class IndexId implements Serializable {
private int seqNo;
private String index;
// getters and setters
}
Then I have the base class:
#MappedSuperclass
public class BaseIndex {
#Id
#Column(name = "seq_no", nullable = false)
protected int seqNo;
#Id
#Column(name = "index", nullable = false)
protected String index;
#Column(name = "value", nullable = false)
protected String value;
//getters/setters
}
Then my entity that will store in the database:
#Entity
#IdClass(IndexId.class)
#Table(name = "bibliographic_single_index")
public class BibliographicSingleIndex extends BaseIndex implements Serializable { }
This is the error I get: Persistent entity 'BibliographicSingleIndex' should have primary key .
I also tried with the properties declared as private and the articles I see on this subject seem to do the same thing.
With these pieces of code is it possible to identify what I'm doing wrong?
I believe every entity needs a separate java class for the id class. You wouldn't have the problem with embedded ids I think.
Imagine I have the following class where all the fields are integers:
#Entity
public class Bar implements Serializable {
#Id
private Integer id;
#Basic
private Integer field1;
#Basic
private Integer field2;
//Constructor & getters/setters omitted
}
Now I wish to have another class Foo which has a HashMap where the keys are fields in Bar with the corresponding values. I.e., something like this:
#Entity
public class Foo implements Serializable {
#Id
private Integer id;
#Basic
private String someString;
#Basic
private Integer someInteger;
#??
private HashMap<String, Integer> barMap;
//Constructor & getters/setters omitted
The reason behind doing this is that I have an an underlying Enum, each value of the Enum should be a column, and then after fetching this as a Map I would have easy access to every field because I already know the names of the properties.
In my mind, the underlying tables would look something like this:
Link to image, as I am not allowed to embed yet.
Is something like this possible? What kind of annotation would it require? I previously tried something as follows in Foo, but it reports that a One-To-One attribute should not be used as a map, so I am probably thinking about this the wrong way.
#OneToOne(mappedBy="Bar")
#MapKey(name="Id")
private HashMap<String, Integer> barMap;
To any future visitors:
I could not find any way to pull this off, and I realized it was probably because it is not good design/practice. Instead, I ended up redesigning my Bar class so that its fields were now the enum and the value, basically transposing the table. The Foo class then simply has a Map<Enum, Bar>. The annotations are:
Foo:
#OneToMany(mappedBy="fooInstance", cascade = CascadeType.ALL)
#MapKey(name="enumField")
private Map<EnumType, Bar> barMap;
Bar:
#Id
#Column(name = "id", unique = true, nullable = false)
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Integer id;
#Column(name="enumField", nullable = false)
#Enumerated(EnumType.ORDINAL)
private EnumType enumField;
#Basic
#Column(name="myField")
private int myField = 0;
#ManyToOne
#JoinColumn(name="fooInstance", nullable = false)
private Foo fooInstance;
I found similar questions, but they did not answer my question.
I have two entities with a many-to-one relationship - unidirectional.
But most importantly, the relationship is lazy. Because it is correct to use a lazy connection, everyone knows it.
Code:
#Entity
public class User implements BaseEntity {
#Id
#Column
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column
private String name;
#ManyToOne(fetch = FetchType.LAZY)
private City city;
}
#Entity
public class City implements BaseEntity {
#Id
#Column
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column
private String name;
}
interface BaseEntity {
void setId(Long id);
Long getId();
}
I wrote a method that allows you to search by the transferred fields of the entity.
An example of how this works:
public class Search<T extends BaseEntity> {
public List<T> getByFields(T entity, List<FieldHolder> data) {
// create criteria with passed field name and value by reflection
}
}
class FieldHolder {
private String fieldName;
private Object value;
/**
* "true" - means that the field "value" contains id related object
* "false" - elementary type like: String, Wrapper, Primitive
*/
private boolean isRelationId;
}
The problem is that problems start when you need to search and related objects - by creating related queries.
The following entry is used to send the associated field: "city.id" and the problem is that when I transfer the essence of the related object (City) it is in a proxy and I cannot get id by reflection from City.
My function works perfectly if you specify:
#ManyToOne(fetch = FetchType.EAGER)
private City city;
But it will greatly affect performance, since I have a lot of related objects. Therefore, I want to solve this problem for a lazy load.
I know that this is not an easy task. But perhaps there is some opportunity to somehow get around this problem.
I have tried several things I found while searching but nothing helped or I did not implement it correctly.
Error I'm getting
Direct self-reference leading to cycle (through reference chain: io.test.entity.bone.Special["appInstance"]->io.test.entity.platform.ApplicationInstance["appInstance"])
Both these extend the base entity and in the base (super class) it has an appInstance as well.
Base entity looks similar to this
#MappedSuperclass
public abstract class BaseEntity implements Comparable, Serializable {
#ManyToOne
protected ApplicationInstance appInstance;
//getter & setter
}
Application entity looks like this
public class ApplicationInstance extends BaseEntity implements Serializable {
private List<User> users;
// some other properties (would all have the same base and application instance . User entity will look similar to the Special.)
}
Special entity
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "objectType")
#JsonIgnoreProperties({"createdBy", "appInstance", "lastUpdatedBy"})
public class Special extends BaseEntity implements Serializable {
#NotNull
#Column(nullable = false)
private String name;
#Column(length = Short.MAX_VALUE)
private String description;
#NotNull
#Column(nullable = false)
private Double price;
#OneToOne
private Attachment image;
#Enumerated(EnumType.STRING)
#ElementCollection(targetClass = SpecialTag.class)
#CollectionTable(name = "special_tags")
#Column(name = "specialtag")
private List<SpecialTag> specialTags;
#Temporal(TemporalType.TIME)
private Date specialStartTime;
#Temporal(TemporalType.TIME)
private Date specialEndTime;
#Enumerated(EnumType.STRING)
#ElementCollection(targetClass = WeekDay.class)
#CollectionTable(name = "available_week_days")
#Column(name = "weekday")
private List<WeekDay> availableWeekDays;
#OneToMany(mappedBy = "special", cascade = CascadeType.REFRESH)
private List<SpecialStatus> statuses;
#OneToMany(mappedBy = "special", cascade = CascadeType.REFRESH)
private List<SpecialReview> specialReviews;
#Transient
private Integer viewed;
private Boolean launched;
#OneToMany(mappedBy = "special")
private List<CampaignSpecial> specialCampaigns;
#Override
#JsonIgnore
public ApplicationInstance getAppInstance() {
return super.getAppInstance();
}
}
All entities in Special inherits from BaseEntity which contains AppInstance
then i have a method to get the special
#GET
#Path("{ref}")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(value = MediaType.TEXT_PLAIN)
public Special findByGuestRef(#PathParam("ref") String pRefeference) {
// find the special and return it
return special;
}
On the special entity I tried the following
Added jsonIgnoreProperties
Added an override for appInstance to annotate with #JsonIgnore
#JsonIdentityInfo
links for the above
https://stackoverflow.com/a/29632358/4712391
Jackson serialization: how to ignore superclass properties
jackson self reference leading to cycle
none of those solutions works. Am I doing something wrong?
Note: Would it also just be possible to edit special, since the other entities are in a different package and would not like to edit them.
Usually excluding attributes in a response is as easy as adding a #JsonIgnore annotation to their getters, but if you don't want to add this annotation to a parent class, you could override the getter and then add the annotation on it:
public class Special extends BaseEntity implements Serializable {
...
#JsonIgnore
public ApplicationInstance getAppInstance() {
return this.appInstance;
}
...
}
NOTE: As there are several frameworks, make sure that you are using the correct #JsonIgnore annotation or it will be ignored, see this answer for instance.
Another option, more "manual", is just creating a bean for the response which would be a subset of the Special instance:
#GET
#Path("{ref}")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(value = MediaType.TEXT_PLAIN)
public SpecialDTO findByGuestRef(#PathParam("ref") String pRefeference) {
// find the special and return it
return new SpecialDTO(special);
}
public class SpecialDTO {
//declare here only the attributes that you want in your response
public SpecialDTO(Special sp) {
this.attr=sp.attr; // populate the needed attributes
}
}
To me, problem seems to be in the Special object and the fields being initialized in it.
I guess that there is a circular reference detected when serialisation happens.
Something similar to:
class A {
public A child;
public A parent;
}
A object = new A();
A root = new A();
root.child = object;
object.parent = root;
In the above code, whenever you will try to seralize either of these objects, you will face the same problem.
Note that public fields are not recommended.
I'll suggest to peek into your Special object and the references set in it.
I got these 2 entities:
#javax.persistence.Entity
public class Book {
#javax.persistence.EmbeddedId
private BookPK id;
private String title;
#javax.persistence.ManyToOne(fetch = javax.persistence.FetchType.LAZY)
#javax.persistence.JoinColumns({
#javax.persistence.JoinColumn(name = "LNGCOD", referencedColumnName = "LNGCOD"),
#javax.persistence.JoinColumn(name = "LIBCOD", referencedColumnName = "LIBCOD") })
private Language language;
}
#javax.persistence.Entity
public class Language {
#javax.persistence.EmbeddedId
private LanguagePK id;
private String name;
}
with composed PK's:
#Embeddable
public class BookPK implements Serializable {
private Integer bookcod;
private Integer libcod;
}
#Embeddable
public class LanguagePK implements Serializable {
private Integer lngcod;
private Integer libcod;
}
If I try to create a new Book and persist it, I get an exception telling me libcod is found twice in the insert statement ("Column 'libcod' specified twice"). But I can't use "insertable = false" when defining the JoinColumn ("Mixing insertable and non insertable columns in a property is not allowed").
Is there any way to define these objects + relationship so the columns are managed automatically by Hibernate ? (I am especially thinking of libcod).
Thank you.
Create a third property "Integer libcod;" on the Book. Have that property manage the db state of libcod. Use insertable=false,updatable=false for both properties in the join to Language. in your "setLanguage" set the private libcod = language.libcod. don't expose a getter/setter for the private libcod.
Are any of the values generated at insert time? This could complicate things further, I suppose.