I need to implement entity property lazy loading. I came with single table inheritance approach.
#Entity
#Table(name = "person")
#Getter
public class Person {
#Id
#GeneratedValue(strategy = IDENTITY)
private Long id;
#Column(name = "firstname")
private String firstName;
}
#Entity
#Getter
public class VerbosePerson extends Person {
#Column(name = "lastname")
private String lastName;
}
public interface PersonRepository extends JpaRepository<Person, Long> {}
public interface VerbosePersonRepository extends JpaRepository<VerbosePerson, Long> {}
Unfortunately, this only works with a discriminator column. Actually, I don't need to distinguish these two entities. All that requires is to exclude lastName column from the Person fetching and to load it only when VerbosePerson is being requested.
One solution is to declare #MappedSuperClass that should have two inherited entities (Person and VerbosePerson). But in this case, Person won't be a supertype for VerbosePerson which is not convenient.
Is there any way to use single table strategy inheritance without discriminators?
It sounds like you need lazy querying and not the inheritance. You should take a look at FetchType annotations
https://thorben-janssen.com/entity-mappings-introduction-jpa-fetchtypes/
Be warned though.. these are primarily used to manage lazy loading for Lists (things that can be easily proxied). Lazily associating a single item (i.e. a #ManyToOne or a simple string, etc.) usually requires some careful object proxying under the covers to ensure it works the way you think it should in your persistence framework. Generally I didn't use it much but I think I did at one point or another to lazily load a class that had variables mapped to a row of a hibernate object that I lazily loaded..
Check out:
https://thorben-janssen.com/lazy-load-non-relational-attributes/#:~:text=The%20JPA%20specification%20defines%20the,value%20must%20be%20eagerly%20fetched.
Pay special attention to the parts:
practices, that means that depending on your JPA implementation, annotating an attribute with #Basic(fetch=FetchType.LAZY) isn’t enough.
Lazy loading for fields requires bytecode enhancement. Then you can use #Basic(fetch = LAZY) and the field will be lazy loaded on first access. Also see https://docs.jboss.org/hibernate/stable/orm/userguide/html_single/Hibernate_User_Guide.html#BytecodeEnhancement
A lot of JPA entity demo classes have the following snippets:
#Id
private Long id;
Can anyone see any drawbacks to always marking the id property as final?
#Id
private final Long id;
It seems like we almost always want to do this in order to preserve the entities identity.
Short answer
It makes using the JPA class impossible.
Elaboration
final is a Java keyword, not a framework keyword. Java doesn't care what the contract for a JPA entity is. You cannot declare a final field that is not uninitialized, since, by contract, a final field can be written only once.
Also, it is not true that ID properties are immutable. For starters, they change when an object is serialized - a null ID is replaced by a generated ID. Less trivially, when an entity is deleted from a database, its ID is nullified.
I have two entities which are bidirectional mapped. A vehicle which has a collection of registrations and the registration itself. These entities are exposed as REST services.
#Entity
#XmlRootElement
public class Vehicle implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String brand;
private String type;
#OneToMany(mappedBy = "vehicle", fetch = FetchType.EAGER)
private List<Registration> registrations;
}
The problem is that the FetchType.EAGER produces an infinite recursion.
#Entity
#XmlRootElement
public class Registration implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#ManyToOne
private Vehicle vehicle;
}
After some researching I figured out that I have to add the annotation #JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") to the Vehicle class to solve the problem.
My question is: What does the PropertyGenerator class actually do?
The problem is not because of FetchType.EAGER. FetchType.EAGER is a JPA annotation and does not come into play when you are serializing an instance of Vehicle using Jackson.
What's actually happening is that Jackson is serializing a Vehicle, which triggers serialization of the list of Registrations, which serializes a Vehicle, which has a list of Registrations, and so on forever.
As you noticed, the #JsonIdentityInfo annotation short circuits the infinite recursion, but it's not because of the specific PropertyGenerator that you have specified. The JavaDoc for #JsonIdentityInfo gives some insight into what's going on:
#JsonIdentityInfo Annotation used for indicating that values of annotated type or property should be serializing so that instances either contain additional object identifier (in addition actual object properties), or as a reference that consists of an object id that refers to a full serialization. In practice this is done by serializing the first instance as full object and object identity, and other references to the object as reference values.
In other words, the first time you serialize something you'll get the full serialized JSON/XML version. The next time that object is serialized then you will get a reference to that first serialized object.
There are other ways to solve this problem too. Check out Infinite Recursion with Jackson JSON and Hibernate JPA issue (your question is arguably a duplicate of this one). The answers there suggest you can also use #JsonIgnore or a combination of #JsonManagedReference and #JsonBackReference to avoid the infinite recursion.
Now, to your specific question about what the PropertyGenerator actually does: it instructs Jackson to use a specific property from your class as the reference to the full serialized version of the object. You specified "id" as the property so in your resulting serialized JSON/XML you should see that if you have an object with ID of 342 then the first serialized object will show the id and all other serialized properties but each subsequent time that object is serialized you will just see the 342 serialized as a reference to the original object.
I have some philosophical intuitive feeling that adding fields which doesn't mapped to the DB corrupts entity classes and is a wrong way of solving problems.
But are there any concrete situations where using #Transient fields leads to implicit and hard fixing problems?
For example, is it possible that adding or removing 2nd level cache will break our app when there are #Transient fields in our entities?
Considerable update: after some thinking on #Transient fields it seems to me that #Transient fields just should be used in a proper way.
By 'proper way' I mean that entity always should have same behavior. It means that it's a very error-prone behavior when getters returns null's from time to time depending on #Transient field value. And it means that #Transient fields should always be initialized.
And I see only 2 cases of proper usage:
#Transient fields should be initialized in object's constructor:
#Entity
public class SomeEntity
#Id
private long id;
#Transient
private String transientField;
public SomeEntity () {
transientField = "some string";
}
...
}
#Transient fields can be lazy initialized:
#Entity
public class SomeEntity
#Id
private long id;
#Transient
private String transientField;
public String getTransientField () {
synchronized (lock) {
if (transientField == null) {
transientField = "some string";
}
}
return transientField;
}
...
}
Can anyone coment these 2 cases or describe other cases which I missed?
I am using the Transient annotation in some projects that persist with hibernate as well and didn't have any problems yet.
It is usually used for fields that can be determined by other persistent properties and using a cache should work also, because Javas Serialization mechanisms (caches usually expect the cached objects to be serializable) take the Transient annotation into consideration, too. I think it is preferrable to use transient getter and setter properties that provide the information instead of instance fields whenever possible.
Java has the transientkeyword. Why does JPA have #Transient instead of simply using the already existing java keyword?
Java's transient keyword is used to denote that a field is not to be serialized, whereas JPA's #Transient annotation is used to indicate that a field is not to be persisted in the database, i.e. their semantics are different.
Because they have different meanings. The #Transient annotation tells the JPA provider to not persist any (non-transient) attribute. The other tells the serialization framework to not serialize an attribute. You might want to have a #Transient property and still serialize it.
As others have said, #Transient is used to mark fields which shouldn't be persisted. Consider this short example:
public enum Gender { MALE, FEMALE, UNKNOWN }
#Entity
public Person {
private Gender g;
private long id;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
public long getId() { return id; }
public void setId(long id) { this.id = id; }
public Gender getGender() { return g; }
public void setGender(Gender g) { this.g = g; }
#Transient
public boolean isMale() {
return Gender.MALE.equals(g);
}
#Transient
public boolean isFemale() {
return Gender.FEMALE.equals(g);
}
}
When this class is fed to the JPA, it persists the gender and id but doesn't try to persist the helper boolean methods - without #Transient the underlying system would complain that the Entity class Person is missing setMale() and setFemale() methods and thus wouldn't persist Person at all.
Purpose is different:
The transient keyword and #Transient annotation have two different purposes: one deals with serialization and one deals with persistence. As programmers, we often marry these two concepts into one, but this is not accurate in general. Persistence refers to the characteristic of state that outlives the process that created it. Serialization in Java refers to the process of encoding/decoding an object's state as a byte stream.
The transient keyword is a stronger condition than #Transient:
If a field uses the transient keyword, that field will not be serialized when the object is converted to a byte stream. Furthermore, since JPA treats fields marked with the transient keyword as having the #Transient annotation, the field will not be persisted by JPA either.
On the other hand, fields annotated #Transient alone will be converted to a byte stream when the object is serialized, but it will not be persisted by JPA. Therefore, the transient keyword is a stronger condition than the #Transient annotation.
Example
This begs the question: Why would anyone want to serialize a field that is not persisted to the application's database?
The reality is that serialization is used for more than just persistence. In an Enterprise Java application there needs to be a mechanism to exchange objects between distributed components; serialization provides a common communication protocol to handle this. Thus, a field may hold critical information for the purpose of inter-component communication; but that same field may have no value from a persistence perspective.
For example, suppose an optimization algorithm is run on a server, and suppose this algorithm takes several hours to complete. To a client, having the most up-to-date set of solutions is important. So, a client can subscribe to the server and receive periodic updates during the algorithm's execution phase. These updates are provided using the ProgressReport object:
#Entity
public class ProgressReport implements Serializable{
private static final long serialVersionUID = 1L;
#Transient
long estimatedMinutesRemaining;
String statusMessage;
Solution currentBestSolution;
}
The Solution class might look like this:
#Entity
public class Solution implements Serializable{
private static final long serialVersionUID = 1L;
double[][] dataArray;
Properties properties;
}
The server persists each ProgressReport to its database. The server does not care to persist estimatedMinutesRemaining, but the client certainly cares about this information. Therefore, the estimatedMinutesRemaining is annotated using #Transient. When the final Solution is located by the algorithm, it is persisted by JPA directly without using a ProgressReport.
If you just want a field won't get persisted, both transient and #Transient work. But the question is why #Transient since transient already exists.
Because #Transient field will still get serialized!
Suppose you create a entity, doing some CPU-consuming calculation to get a result and this result will not save in database. But you want to sent the entity to other Java applications to use by JMS, then you should use #Transient, not the JavaSE keyword transient. So the receivers running on other VMs can save their time to re-calculate again.
In laymen's terms, if you use the #Transient annotation on an attribute of an entity: this attribute will be singled out and will not be saved to the database. The rest of the attributes of the object within the entity will still be saved.
Im saving the Object to the database using the jpa repository built in save method as so:
userRoleJoinRepository.save(user2);
For Kotlin developers, remember the Java transient keyword becomes the built-in Kotlin #Transient annotation. Therefore, make sure you have the JPA import if you're using JPA #Transient in your entity:
import javax.persistence.Transient
I will try to answer the question of "why".
Imagine a situation where you have a huge database with a lot of columns in a table, and your project/system uses tools to generate entities from database. (Hibernate has those, etc...)
Now, suppose that by your business logic you need a particular field NOT to be persisted. You have to "configure" your entity in a particular way.
While Transient keyword works on an object - as it behaves within a java language, the #Transient only designed to answer the tasks that pertains only to persistence tasks.