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

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

Related

Hibernate ignores constructor and setters

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.

add softly linked attribute spring-data-rest?

I have just a straight forward question.
Just imagine I have an entity class which is mapped to a table with columns. I just need to introduced a new attribute to the same class, whose value needs to be fetch from a column in another table (What I mean by softly linked).
I know this is not quite a clean requirement.
Anyway, is it possible?
Not sure if this is what you're looking for, but here - you can possibly extend the entity.
Say your entity class is Drink
class Drink {
String weight;
String size;
//other getter setter constructor etc
}
And then you have a service from which you are able to fetch a value from a column:
class FlavorService {
static String getFlavor(){ /*can be static since it's only retrieval/idempotent*/ };
}
So now what you can do is create an extended class
class FlavoredDrink extends Drink{
String flavor;
public FlavoredDrink (String weight, String size){
super(weight, size);
this.flavor = FlavorService.getFlavor();
}
}
Then you just have to use FlavoredDrink.

Polymorphism and tree structre

After asking the following question before : rest api and polymorphism
I wonder maybe my whole db schema and class structure is wrong.
the current structure is:
PERSON BASE ABSTRACT CLASS contains name and and age
CHILD EXTENDS PERSON contains favorite TV show
PARENT EXTENDS PERSON contains a list of children
GRANDPARENT EXTENDS PERSON contains a list of parents
In db the tables organized in table for each subtype
I thought of maybe refactoring the classes since the subtybes don't add any valuable fields, except to list of children/parents to this, only one class that include all the
fields:
#Entity
class Person{
#ManyToOne
private Person parent; //parent==null is a grandparent
#OneToMany
private List<Person> children;
}
However, the problem with this is that in my business logic, parent child and grandparent do have different behaviors, and this way its harder to distinguish
furthermore, a child parent can not be a grandparent.
Another problem is, say I am staying with the current class structure
separating the classes doesn't really helps me because I am using a service layer
and I have no way to no which service class I need, example :
class PeopleController extends Controller {
public Result savePerson() {
Person p = objectMapper.readValue.. // deseralizes to correct subtype
// saving logic is different for each subtype, hence I need to
// find correct repository for this subtype but I don't want to use
// instance of or switch case, but to use polymorphism, but can't think
of a way without implementing active record which I don't want
}
}
The determination of type can be completely determined based on state and it doesn't require the use of polymorphism as your question hasn't provided any real basis for using it in the first place. The attributes you've defined as collecting seem reasonable for all Persons.
A Parent is any person that contains a non-empty child set.
All Person instances constitute a Child, but for this exercise it could imply any person that contains an empty child set.
A GrandParent is any person that is a Parent, but also requires that at least one of its instances in the child set be a Parent.
With that in mind, we could consider restructuring the data model as follows.
#Entity
public class Person {
#Id
#GeneratedValue
private Integer id;
private String name;
private Integer age;
// any person can have this, not just children imo :)
private String favoriteShow;
#OneToMany(mappedBy = "parent")
private Set<Person> children;
#ManyToOne
private Person parent;
#Transient
public boolean isChild() {
return children == null || children.isEmpty();
}
#Transient
public boolean isParent() {
return !isChild();
}
#Transient
public boolean isGrandParent() {
return isParent()
&& children.stream().filter( Person::isParent ).count() > 0;
}
}
Even with this approach, your logic can branch based on the boolean transient method checks. There are ways you can optimize these methods of course but I wouldn't be too worried about that as these checks are already well optimized on JDK8.
The benefit here though is you can simply have a Person service your controller interacts with and most likely a Person repository since the data is aligned as one type.
I realize your saving logic is different per type, but my question is does it really have to be different? Perhaps more in-depth reasoning why these need to be split can help give us more context.

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.

Method in parent class that returns child class in java

I have a parent class Product and some children class like Camera, TV, etc...
Now I want to create a method in Product that fetches from db common attributes to all children and returns an instance of a child, according to the object fetched from the db (I have a lot of children class).
Is it possible to do this? If yes, can you show me a little example?
My idea is to call this method from a similar method in child class and then fetching from db all those non-common attributes.
First, it seems like you'd want to put the db access code into your classes, which I wouldn't recommend.
As for your real problem: try and use an ORM framework such as EclipseLink or Hibernate. Those use a discriminator column to determine the actual class of an entity and create and populate the instance for you. As an alternative (if you can decide on the database) you could also have a look at ObjectDB.
I think you should have a look at decorator pattern
http://javarevisited.blogspot.co.uk/2011/11/decorator-design-pattern-java-example.html
public class Product{
int productId;
protected Product(int productId){ //avoid creating pure product objects
this.productId = productId;
//load all the common properties
}
public Product getProduct(int productId){
// read the product with productId from the table
// identify the type of the product
String type = .... (assume its "camera")
if("camera".equals(type)){
return new Camera(productId);
}
}
}
in the child class,
public class Camera extends Product{
public Camera(int productId){
super(productId);
}
}
usage
Product p = Product.getProduct(4025);
the method will load the relevant field from the database, identify the type of the product, create a subclass object based on the type of the product and call its constructor.
the constructor of the child class calls the super class constructor.
the super class constructor loads all the common properties.

Categories