Why to use #AllArgsConstructor and #NoArgsConstructor together over an Entity? - spring-boot

I have seen multiple codes online on applications of Spring Boot in IntelliJ, and many use both #AllArgsConstructor and #NoArgsConstructor together and both are constructors however the purpose of each is different -
#AllArgsConstructor generates a constructor requiring argument for every field in the annotated class
#NoArgsConstructor generates a constructor with no parameter
Then why are we using both together over the same entity and how do they function in such case?
#Data
#AllArgsConstructor
#NoArgsConstructor
#ToString
#Entity
public class Product {
#Id
private int id;
private String name;
private String type;
}

The JPA specification requires that all persistent classes (#Entity) have a no-arg constructor, public or protected. (note that this is not necessarily true when dealing with some implementation like Hibernate, see this answer).
This is needed because JPA uses the default constructor method to create a bean class using the reflection API. Indeed if your class would contain many constructors then JPA wouldn't know which one to call, this is why it instantiates the class through its no-arg constructor using reflections :
Product.class.newInstance();
which is equivalent to new Product() (Product.class is a class literal, it can fail at runtime if the class is not found in the classpath), then, once instantiated, uses fields setters to deal with it.
Then, in Java, a default constructor (no-argument constructor) is automatically generated for a class unless you define other constructors (it only does when you don't provide any other constructor).
So because the compiler automatically creates a default no-arg constructor when no other constructor is defined, only classes that define constructors must also include a no-arg constructor if required by a framework (here JPA). This is why you need to add #NoArgsConstructor annotation if you add the #AllArgsConstructor annotation.
Also note that you are using #Data, which bundles the features of #RequiredArgsConstructor, which will generate a constructor for all final or #NonNull annotated fields (see Lombok documentation). So as you are using only non final nullable fields, it may generate an empty constructor even if you don't add the #NoArgsConstructor annotation. I have not tested that last case though, I know that it generates an empty constructor when using #RequiredArgsConstructor directly with non final nullable fields, but I don't know if it works the same when using #Data.
#Data also bundles #ToString, so you don't need to add it again.
I'm personnaly not a fan of using #Data if I don't need all the bundled annotations, so I usually simply use :
#Entity
#Getter
#Setter
#EqualsAndHashCode
public class Product {
#Id
private int id;
private String name;
private String type;
}
as I often don't use toString() nor parameterized constructor. It may be more verbose but more meaningful to me.

These are the annotations from Lombok. To understand why it's is needed you have to understand how things work internally.
JPA says
It's specification says "The JPA specification requires that all persistent classes have a no-arg constructor. This constructor may be public or protected. Because the compiler automatically creates a default no-arg constructor when no other constructor is defined, only classes that define constructors must also include a no-arg constructor."
To understand further, when it creates and entity using reflection it uses Class.newInstance() method which requires a no-argument constructor to create an instance.
The most common type of dependency injection used by Spring is
Constructor based Injection
Setter based Injection
Constructor based Injection (#AllArgsConstructor): When you create object by passing all parameters, you basically use a constructor injection. It should be done when we have all parameter values and we want to create an object with all values initialized.#AllArgsConstructor generates a constructor requiring an argument for every field in the annotated class.
Setter based Injection (#NoArgsConstructor): We create an object first (uses no arg-constructor) and then update the dependencies or values later by using setters.#NoArgsConstructor generates a default constructor with no parameters.
There are many key differences between constructor injection and setter injection.
Partial dependency: can be injected using setter injection but it is not possible by constructor. Suppose there are 3 properties in a
class, having 3 arg constructor and setters methods. In such case, if
you want to pass information for only one property, it is possible by
setter method only.
Overriding: Setter injection overrides the constructor injection. If we use both constructor and setter injection, IOC container will
use the setter injection.
Changes: We can easily change the value by setter injection. It doesn't create a new bean instance always like constructor. So setter
injection is flexible than constructor injection.
#NoArgsConstructor will generate a constructor with no parameters. If this is not possible (because of final fields), a compiler error will result instead, unless #NoArgsConstructor(force = true) is used, then all final fields are initialized with 0 / false / null. For fields with constraints, such as #NonNull fields, no check is generated,so be aware that these constraints will generally not be fulfilled until those fields are properly initialized later. Certain java constructs, such as hibernate and the Service Provider Interface require a no-args constructor. This annotation is useful primarily in combination with either #Data or one of the other constructor generating annotations.
#AllArgsConstructor generates a constructor with 1 parameter for each field in your class. Fields marked with #NonNull result in null checks on those parameters.
Conclusion:
#AllArgsConstructor generates a constructor requiring an argument for every field in the annotated class.
#AllArgsContstructor also allows the creation of static factory
methods using the staticName attribute
#NoArgsConstructor generates a default constructor with no parameters
#NoArgsConstructor can create a static factory method for construction purposes
Lombok can't call the super constructor unless it has a no-args constructor
If the superclass doesn't have a no-args constructor, Lombok can't generate any constructor in the subclass

Related

MappedSuperclass produces 'has an unbound type and no explicit target entity'

I have this entity. It should work on both, internal and external, users.
#Entity(name = "TokenAuthentication")
class TokenAuthenticationEntity<T>(
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long? = null,
...
#NotNull
#ManyToOne(fetch = FetchType.EAGER)
val user: T,
) : BaseEntity()
When I run this, I get
Property TokenAuthenticationEntity.user has an unbound type and no explicit target entity. Resolve this Generic usage issue or set an explicit target attribute
So Hibernate tells me to f*** off with my generics, it needs explicit definitions. Any of you have an idea how to get this running with generics?
This is not possible. The reason being T type erasure at compile-time. This T type is used at compile-time to check types and guarantee type safety, but then it is removed. Having said that, each instance of TokenAuthenticationEntity can have a different value for T, and as explained before this information is lost.
What you can actually do is the following:
#MappedSuperclass
public abstract class TokenAuthenticationEntity<T> {
private T user;
}
Now you can create your entities based on this generic superclass:
#Entity
public class InternalUser extends TokenAuthenticationEntity<IUser> { }
#Entity
public class ExternalUser extends TokenAuthenticationEntity<EUser> { }
Why? Because each concrete subclass of TokenAuthenticationEntity has a type T which is defined and is retained and unique inside the subclasses. In this case, JPA will store your subclasses in one or more tables, depending on the chosen #InheritanceStrategy (if the Inheritance annotation is not specified or if no inheritance type is specified for an entity class hierarchy, the SINGLE_TABLE mapping strategy is used). Additional details at https://www.baeldung.com/hibernate-inheritance#single-table.

Load Spring configuration in Hibernate entity

I want to configure Hibernate to set maximum length for a VARCHAR field. This maximum length is defined in a configuration file, and this configuration file is loaded by a class ValidationConfiguration.
This is my entity:
#Entity
public class MyEntity{
#Autowired /*I know this is bad practice,
I just want to let readers know that this object is instantiated.*/
private ValidationConfiguration config;
#Column(length = config.getMaxLength()) /*This gives a "java: element value
must be a constant expression"*/
String description;
//Get and set
}
Is this possible? If not, are there any workarounds?
From your code, it is clearly visible, that You are just defining the ValidationConfiguration by private ValidationConfiguration config;
But You are not Instantiating the Object.
So, Instantiate the object like new ValidationConfiguration() and since you haven't shared the code of ValidationConfiguration , i am predicting that your method is getMaxLength() not static. If the problem persists, do share the ValidationConfiguration code.
If that is a bean, then you can autowire it simply and don't create new instantiation.

Using #Configurable domain object properties to assign a specific behaviour based on data

I have a domain object which looks like this.
i need to use the data fetched from the database ("type" in this example) to fetch and inject the correct type of service.
I get this output which means that the DB data are not set during the call :
entity is a bean postconstruct: PocProduct [id=null, type=null, productName=null].. attching behavior!
I get the same resilt when I try with the initializing Bean.
What is the correct way to configure this?
#Entity
#Table(name = "AAA_POC_PROD")
#Configurable(dependencyCheck = true)
#Scope("prototype")
public class PocProduct implements Serializable, InitializingBean {
/**
*
*/
private static final long serialVersionUID = 1136936011238094989L;
#Id
private String id;
private String type;
private String productName;
#Transient
private Behaviour behaviour;
#Transient
#Autowired
private BehaviourFactory behaviourFactory;
//getters and setters
#PostConstruct
public void attachBehavior() {
System.out.println("entity is a bean postconstruct: " + this + ".. attching behavior!");
//Need to call this : depends on type which is fetched from DB
// this.behaviour = behaviourFactory.getTypeBasedBehaviour(type);
}
}
Configurable beans are initialized by Spring after or before construction, depending on the value of the #Configurable.preConstruction attribute. When loading an entity from a database this means the following sequence of events:
The JPA provider creates the entity by invoking it's constructor via reflection
While the constructor executes, spring-aspects' AnnotationBeanConfigurerAspect intercepts the constructor execution and, before (or after) the constructor executes, Spring will configure this newly created object by executing any bean configuration you have in your spring context, including autowiring of properties.
The JPA provider will receive this object already configured by Spring and will start populating its persistent properties with data fetched from the DB.
Optionally, if you set up #PostLoad methods, the JPA provider will invoke these methods so that your entities have a chance to do work after the entity is fully populated by data from the DB.
From what I see you're trying to do, this 4th step is where you should put your custom behavior logic, assuming everything else is working properly.

Jpa + Spring - automatically setting transient field value after read from DB

what's the best solution to set a value for a field marked #Transient after the entity has been read from the data source?
I'm using EclipseLink and I'm trying the DescriptorEventAdapter with his postBuild event solution because I need also to get the default value using a Spring bean (obviuosly using DI), but I would know if there is any simpler solution that I'm missing.
Thanks in advance
Here's the simple approach if you're using a repository or DAO:
#Repository
class YourRepository {
#Autowired
private Bean bean;
#PersistenceContext
private EntityManager entityManager;
#Transactional(readOnly = true)
public YourEntity find(..) {
YourEntity entity = lookupUsingEntityManager();
entity.transientField = bean.getDefaultValue();
return entity;
}
}
Here's another approach if you are using active record -style entities:
#Entity
class YourEntity {
#Transient
public Object field;
#PostLoad
public void populateField() {
field = new BeanHolder().bean.getDefaultValueForField();
}
#Configurable
private static class BeanHolder {
#Autowired private Bean bean;
}
}
Mind the semi-pseudo-code. Note that the latter approach works only if you use compile- or load-time AspectJ weaving with <context:spring-configured />.
You got entity which has transient field and the value is always taken from service using DI?
What is the purpose of the field? It's used for some calculation within any entity method?
Such calculation should probably use service's method to obtain the value.
As value from any service is used, I'm not sure whether such calculation (method) belong into entity.
Note that entity and service has completely different lifecycle. The value is changing in the time so it does not make the sense to supply the value in entity's factory at the beginning of it's life?

ObjectTypeConverter not found within persistence unit

In my project I use an enum in some entities. The enum is to be stored in the database as an integer. To achieve this I use EclipseLink's ObjectTypeConverter.
I'd like to use annotations since I use Spring to omit the persistence.xml. The annotation to configure the ObjectTypeConverter must be specified on an entity. I don't feel the need to specify the annotation on all classes that use this enum as this is redundant and not maintainable. Specifying it once on some entity would work but this doesn't make sense in an OOP design (or any design for that mater). A solution would be to annotate the enum with #ObjectTypeConverter, but this doesn't work since the enum isn't an entity.
Example that isn't working but would be ideal:
#Entity
public class ExampleEntity
{
#Id
private Long id;
#Convert("exampleenum")
private ExampleEnum ee;
}
#ObjectTypeConverter(name = "exampleenum", objectType = ExampleEnum.class, dataType = Integer.class,
conversionValues =
{
#ConversionValue(objectValue = "A", dataValue = "100"),
#ConversionValue(objectValue = "B", dataValue = "200"),
#ConversionValue(objectValue = "C", dataValue = "300")
})
public enum ExampleEnum
{
A, B, C;
}
Example results in the following exception:
Exception Description: The converter with name [exampleenum] used with the element [field ee] in the class [class com.example.ExampleEntity] was not found within the persistence unit. Please ensure you have provided the correct converter name.
Since I'm using Spring, JPA and EclipseLink I accept any answer using these frameworks.
Upon reading the documentation (which I should have done more carefully in the first place) I noticed:
An ObjectTypeConverter must be be uniquely identified by name and can be defined at the class, field and property level and can be specified within an Entity, MappedSuperclass and Embeddable class.
I couldn't annotate the enum with #Entity (as this requires a table) or #MappedSuperclass (as this doesn't make sense), but #Embeddable would make sense in a way. Marking the enum with #Embeddable did the trick:
#Embeddable
#ObjectTypeConverter(...)
public enum ExampleEnum
...

Resources