Hibernate ignores constructor and setters - java

I encountered an odd behavior when I tried to load some Objects from my Database using Hibernate 5.4.3.
Let's say I have a Class A which contains an instance of Class B. Now I want to load Class A from my Database but for some instances of A B is null. To prevent that there are A's with B's that are null I used the code below:
#Entity
public class A{
#Id
#GeneratedValue
private Long id;
#OneToOne(cascade = CascadeType.ALL)
private B b = new B();
public setB(B b){
if(b == null){
this.b = new B();
}else{
this.b =b;
}
}
public B getB(){
return this.b;
}
}
Now when I use A's somehow I still get A's that have no instance of B. How is this possible?

Well, business logic in getters / setters is at least dubious, especially if passing a null to a setter results in something as weird as a new blank object being assigned.
Hibernate doesn't need setters to build entities, it can do so with reflection. You can use property access, meaning setters are used, but for this use case I would not do that. Keep your getters / setters clean, and instead go for #PostLoad like XtremeBaumer suggested, or even better, keep them as nulls since that's what they are. I'd be terrified if my database nulls turned into some weird zombie objects on load.

Related

In my constructor, is it bad practice to set class variables by calling getters on an object I pass into a constructor?

So imagine I have a simple class with three variables which are ultimately derived from another object. I could insert that other object in the constructor like:
public class A {
private int x;
private int y;
private List<> list;
public A(B b) {
this.x = b.getX();
this.y = b.getY();
this.list = b.getList();
}
}
public class B {
private int x;
private int y;
private int z;
private String string;
private Set<> set;
private List<> list;
//constructor, setters and getters
}
A colleague has suggested I should instead do the following:
public class A {
private B b;
public A(B b) {
this.b=b
}
}
Now in the application using their option will require a lot of refactoring from
a.getX() to a.getB().getX() or a.getList() to a.getB().getList() for example.
What I'm struggling to find is what is there some best practice defined in this scenario and why.
My argument is I don't want objects that use A to be coupled to any class structure imposed by B. I think my colleague is concerned that my constructor should not be accepting B as an argument only to call getters on it's variables within the constructor of A.
An alternative would be to use a factory or something to create A from B but that isn't really feasible with my use case. (In my specific use case A is being constructed in a HQL query and B is an Entity class)
EDIT:
I typed this question out on my phone but realise I missed some details so will add them here.
A consists of a subset of properties from B. A also consists of a subset of properties of another class C. The properties of C are currently individually assigned in the constructor in what you would consider a normal manner (because there are only a few). Because A takes a lot of properties from B I am inserting it in the manner illustrated above.
B and C are Entity classes that represent a row from two separate (but related) tables.
A is a class which is we use to do some business logic with somewhere else.
Maybe this is what you are looking for. A is a more general type and B is a more specialize type of A. For example, a Person class and a Student class.
public class A {
private int x;
private int y;
private List<> list;
public A(int x, int y, List<> list) {
this.x = x;
this.y = y;
this.list = b.getList();
}
}
public class B extends A {
private int z;
private String string;
private Set<> set;
public B(int x, int y, List<> list, String string, Set<> set){
super(x,y,list);
this.string = string;
this.set = set;
}
}
With all the information that you have given, your colleague's suggestion of having B object as a class field of A is a bad design. As well as passing B on the A constructor.
The main problem here is on the A class constructor, not it's field.
Passing B object directly to A constructor is a bad design/practice even if A takes a lot of properties from B. If someone were to construct an A object that takes B as an argument, most of the time they would assume that A uses B or that they have a strong relationship. If your concern here is avoiding a lengthy constructor, then you're better off using A setters to take the B properties as shown below:
A aClass = new A();
aclass.setX(bClass.getX());
aclass.setY(bClass.getY());
Another way is creating a method in class A that takes required properties from B by taking B as an argument like:
public class A {
\\fields
public void setRequiredPropertiesFromBClass(B bClass) {
this.x = bClass.getX();
\\\other getters
}
}
That way the intent of your code is clear, which is A needs certain properties from B not B itself. The example above can still be improved. I couldn't think of much better method name since I don't really know the complete implementations of these classes. Lastly, you mentioned that B and C are related so you can turn the method into a generic one so it can take B and C.
If all of these suggestions are still not helpful. Just search for Transfer Object Pattern on the internet.
So I resolved this by creating a static mapper like this;
public class Mapper {
public static A mapToA(B b) {
return A.builder()
.x(b.getX())
.y(b.getY())
.list(b.getList())
.build();
}
}
Obviously the mapper holds the relationship between A and B (and in my case also C).
As mentioned above A is a DTO and B and C are database entities. The existing application was actually quite poorly written with the Repository interfaces directly returning the DTO A as part of a HQL query. I changed these to directly return B and C and then mapped these to A in the service classes.

rest api with spring : Create a new entity based on another one

I'm new to java and spring. I have two classes
Class 1
class A {
Long id;
String attr1;
String attr2;
//getters & setters
}
Class 2
class B {
Long id;
String attr1;
String attr2;
String attr3;
String attr4;
#ManyToOne
A a;
//getters & setters
}
I want when I call my api by giving the id of an existing object of class A, I'll be able to insert the common attributes to the new object of class B.
Please what's the best way to to do this
what do you think about doing that way ?
#PostMapping("/test/{idObjectA}")
public B createNewB(#PathVariable Long idObjectA, #RequestBody B objectB){
//verify if ids are null..
A objectA = aRepository.getAbyId(idObjectA)
objectB.setAttr1(objectA.getAttr1);
objectB.setAttr2(objectA.getAttr2);
objectB.setA(objectA);
B result = bRepository.save(objectB);
return result;
}
You said REST, then follow the REST.
From your description, it looks like Object A is a container type and could have multiple instances of A (based on id), e.g. jobs object would have job-id
With that in mind
/test/A [HTTP POST] // POST, GET, PUT at container object level
To an item of A
/test/A/{id} // POST, GET, PUT at container's item level
To create a child resource B of A
/test/A/{id}/B // POST, GET, PUT at B level (which is a child of A)
Since you used #ManyToOne for B, it seems an instance of A could have multiple child items B
To access B
/test/A/{id}/B
To access an item of B
/test/A/{id}/B/{id}
A real life example of something like this would be:
mycompany/jobs/123/positions/1
Finally a word of note:
For most cases, you can use #OneToMany for Entity A (instead of #ManyToOne on entity B), because usually you would need to access child from parent. But if you need to access parent from child too, you could do bidirectional. i.e. use #OneToMany in Entity A and #ManyToOne in Entity B.
Coming to your question about using common properties between Object A and B
Some context first:
You can inherit properties (by same name) form a base entity. For example if you have a "person" as base entity - it could have name, last name, age etc. now an "employee", "manager" etc can inherit from "person". But in this example, person could really be an abstract class since you will create a person entity on its own. See this to learn more.
In a different example, if you have a "children" entity inherited from "parent" - both of these could independently exist and they could have same property names (name, last_name, age etc) - but they will have different data.
In your case it seems you not only want to have same properties for entity A and B, but you actually want to share the same data. That is a wrong design. It is not normalized DB design. You should ideally have no data duplication in DB.
But if you must do that (for some inexplicable reason), you can do something like this (use composition instead of inheritance):
Class SharedData{
String sharedAttr1;
String sharedAttr2;
}
Class A{
SharedData sharedAttributes;
String attrA1;
#OneToMany(). // if you want navigation from A to B
B b;
}
Class B{
SharedData sharedAttributes;
String attrB1;
#ManyToOne // if you want navigation from A to B
#JoinColumn(name="<identity_column_of_A>", nullable=false)
A a;
}

Java cast base class to an extended class

i have a class that is used widely in my project as some sort of field holder. Something like:
class A
{
private String field = null;
private String field2 = null;
private String field3 = null;
// and its generic Getters and Setters
}
In certain part of code i need add additional fields to this class. So i did this
class B extends A
{
private String fieldInB = null;
// and its Getters and Setters
}
in my function i thought i could easily do
public void foo( A a )
{
B b = (B)a;
}
And i could have all the fields written in aobject and i could easily set only field in b and use it. This seams like a common problem, but i just don't know how to do it except with an very ugly approach:
public B( A a )
{
// copy all the fields one at the time
}
You areconfusing different parts of Java:
B b = (B)a;
this is classical class cast, but to work with B class object you need:
1. be sure that a is of B class (check it with instanceof java keyword:
if (a instanceof B) {
B b = (B) a;
}
2. or wrap a in B class object (create B class object with copying fields from a).
PS in most of Java coding conventions it is recommended to fill fields by concrete values only (and not fill with default JavaVM values - nulls)
Comfortable way to copy A class fields to new instance:
public A (A a) {
this.field = a.field;
this.field2 = a.field2;
this.field3 = a.field3;
}
and for B class:
public B (A a) {
super(a);
}
Another way - some libraries that will work with A class and B class as with beans. Sample of this libraries you can find in Toilal's answer
You could use Dozer. It allows to map bean property values from one bean class to another.
Hai john Actually i didn't get your exact requirement. I recon the way you have written this code is not right.
Private variable cant be inherited.If you need to extend values to your subclass you should have declared those variables as public.
public B(A a)
{
super.field=a.field;
super.field2=a.field2;
super.field3=a.field3;
}

Java deepclone an object without some properties

I have following classes
class A {
private Long id
private List<B> listB;
private C c;
...
}
class B {
private Long id
private A a;
private List<D> listD;
...
}
class C {
private Long id
private A a;
...
}
class D {
private Long id
private B b;
...
}
I need a copy of A, include all of it's properties except all id column.
I have 2 solutions:
1. Clone each object and set all of the ids null;
2. Make a constructor like this:
public A (A a){
//copy all properties except id
this.xxx = a.xxx;
...
}
But i need write so much code for this function, any one has some better method to implement this function?
Thanks a lot.
When you are saying Deep cloning of the object particularly the one of type Class A where you have an instance variable of a container type, you have below two widely known ways:
1) You Serialize and Deserialize the object.
2) You traverse through each method and call clone explicitely.
For first implementation, you may mark the id fields as transient and that should solve your purpose.
For second approach, you may override the clone method in each class where you set the id field as 0/-1) and call super.clone()
You can use Mapstruct , it's a powerful mapping library where you can configure all the fields exclusions for your specific class or nested class, without having to write all the getters/setters manually.
I personally use it for deep cloning jpa entities excluding ids or auditable fields.
Ex:
#Mapping(target="id",ignore=true")
EntityA cloneEntityAWithoutId(EntityA origin);
Mapstruct will generate for you the implementations using getters and setters of the EntityA, excluding the id field.
Obviously is a lot configurable, see the documentation I shared above.

jpa inheritance and code reuse in service classes

I have a parent entity, Person, and two children entities : Caller and Employee. The two children share a lot of fields so i implemented JPA inheritance with single table strategy and discriminator column.So far so good.
In order to handle these objects i have some Service classes that handle database operations where i have methods like : getCallerById(); or getEmployeesByFirstName(). Also the save() methods are in these service classes. The problem is that when i want to save an employee or an caller i got a lot of duplicate code (for all the shared properties), so in order to prevent this i created a 3rd service: PersonService() in order to handle the common functionality. But now i do not know how to use this service in order to reuse as much code as i can.
Maybe in the PersonService() to have something like
public Boolean save(Person p){
if (p instanceOf Caller){
Caller c = new Caller();
c.setCallerSpecificProperty("XXX");
}
if (p instanceOf Employee){
Employee c = new Employee()
c.setEmployeeSpecificProperty("YYY");
}
c.setOtherCommonParameter("ccc");
//............
}
or how do you advise me to handle this problem???
Thanks
if your problem is just to set the 100 commonProperties of Person, you can add helper method, say
protected Person setCommonProperties(Person p){
p.setFoo(foo);
p.setBar(bar);
...
p.setWhatever(blahblah);
return p;
}
in your parentService( PersonService in your case)
And in your sub classes, (e.g. CallerService),
boolean save(){
Caller caller = new Caller();
caller = setCommonProperties(caller);
caller.setCallerPropertyA(...);
caller.setCallerPropertyB(...);
...
//save caller
return true or false;
}

Categories