Map Table Record into JPA Entity - java

I have two classes TableNameA and TableNameB inside two different dependencies DependencyA and DependencyB representing tables table_name_a and table_name_b with fields described below.
TableName: table_name_a
Field's Name: field_name_p, field_name_q, field.
TableName: table_name_b
Field's Name: field_name_r, field_name_s.
#Entity
#Table(name = "table_name_a")
#Data
#AllArgsConstructor
#NoArgsConstructor
public class TableNameA{
#Id
private int field;
private int fieldNameP;
private int fieldNameQ;
}
#Data
#AllArgsConstructor
#NoArgsConstructor
public class TableNameB{
#Column(name = "field_name_r")
private int fieldNameR;
#Column(name = "field_name_s")
private int fieldNameS;
}
log.info(dslContext.selectFrom(TableNameA.TABLE_NAME_A)
.limit(4)
.fetch()
.into(dependencyA.TableNameA.class).toString());
log.info(dslContext.selectFrom(TableNameB.TABLE_NAME_B)
.limit(4)
.fetch()
.into(dependencyB.TableNameB.class).toString());
I am using jooq as explained above and I want to map table_name_a and table_name_b record into TableNameA and TableNameB class but in the object of TableNameA only 'field' member variable is mapped properly and rest of member variable's fieldNameP, fieldNameP are mapped to null rather than corresponding values in column of table and TableNameB is mapped properly.
The issue here is member variable's fieldNameP, fieldNameP are mapped to null rather than corresponding values in column of table
And One more condition i can't edit TableNameA and TableNameB classes instead I have to write my own models to map if i don't get solution for this.

What you describe is a known issue in jOOQ: https://github.com/jOOQ/jOOQ/issues/4586. Also the fields without a #Column annotation should be mapped, unless they are annotated as #Transient. The reason field gets mapped properly is that it has an #Id annotation.
For the time being I suggest you vote for the linked GitHub issue so that the issue gets attention and can be properly prioritized.

Related

way to change the jsonProperty name in only one use case

I have one model class which has approximately 100 property fields. I need to change the jsonProperty name's for one usage scenario but in all other cases where i'm using this class the property name should not be change. What would be the ideal way to handle this situation.
List<DebitTable> debitTableList = getListData();
Below is the DebitTable class.
#Validated
#Data
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Setter
#Builder
public class DebitTable {
#JsonProperty("debitId")
private Long debitId;
#JsonProperty("debitName")
#Pattern(regexp = "^[a-zA-Z0-9 ]*$")
#Size(max = 10)
private String debitName;
.....
}
In one of the usage which returns this List<DebitTable> , i want to change the jsonProperty name from debitId to "Debit Id" and "debitName" to "Debit Name"...Do i need to create another model class by changing the jsonProperty name,but that would be very difficult to set each and every field from one model DebitTable class to other new model class.

Using Java records as JPA embeddables

I want to use Java records as embeddable objects with JPA. For example I want to wrap the ID in a record to make it typesafe:
#Entity
public class DemoEntity {
#EmbeddedId
private Id id = new Id(UUID.randomUUID());
#Embeddable
public static record Id(#Basic UUID value) implements Serializable {}
}
But If I try to persist it with Hibernate 5.4.32 I get the following error:
org.hibernate.InstantiationException: No default constructor for entity: : com.example.demo.DemoEntity$Id
at org.hibernate.tuple.PojoInstantiator.instantiate(PojoInstantiator.java:85) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.tuple.component.AbstractComponentTuplizer.instantiate(AbstractComponentTuplizer.java:84) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
...
So it looks like Hibernate would treat the record Id like an entity, although it is an #Embeddable.
The same happens with non-id fields and #Embedded:
#Embedded
private Thing thing = new Thing("example");
#Embeddable
public static record Thing(#Basic String value) implements Serializable {}
Is there a way to use #Embeddable records with JPA/Hibernate?
Java records with a single field can be used for custom ID types or any other value object with AttributeConverters.
In the entity class the ID type is used with #Id as usual:
#Entity
public class DemoEntity {
#Id
private Id id = new Id(UUID.randomUUID());
public static record Id(UUID value) implements Serializable {}
}
Note that the record Id doesn't have any annotation.
The converter makes it possible to use records:
#Converter(autoApply = true)
public class DemoEntityIdConverter implements AttributeConverter<DemoEntity.Id, String> {
#Override
public String convertToDatabaseColumn(DemoEntity.Id id) {
return id.value().toString();
}
#Override
public DemoEntity.Id convertToEntityAttribute(String s) {
return new DemoEntity.Id(UUID.fromString(s));
}
}
Don't forget to set autoApply = true to have this converter applied automatically (without referencing it explicitly on the respective field).
Records with more than one field could be mapped with a Hibernate UserType, but that is a bit cumbersome.
Entity or embeddable, in any case the record class wouldn't be suitable here because entities and their fields, including embeddable ones, are modifiable. The only exception would be for Id fields, but that doesn't seem like an important enough case to make this functionality for.
One of the Hibernate developers explains this here

Using Index annotation on superclass with Hibernate

I have an abstract superclass which every Entity on my domain is a subclass of it.
Using DB schema generation, I want to create an Index for each Entity, on a field on the superclass, and without using the Table annotation on every subclass.
My superclass
#MappedSuperclass
public abstract class BaseEntity {
#Id
#GeneratedValue(strategy = SEQUENCE)
private Long surrogateId;
#Index(name="id_index") // Every subclass should inherit this index, with its own name
#Column(unique = true, updatable = false, nullable = false)
private UUID id = UUID.randomUUID();
An example of subclass
#Entity
public class Customer extends BaseEntity {
...
}
I tried so far:
use the Table annotation with #Index on the superclass, but Hibernate
doesn't seem to use that annotation if it is not marked with #Entity.
For example
#Table(indexes = {#Index(name="index_id", columnList = "id")})
No SQL statements are generated.
use the deprecated #Index annotation with a name "id_index", but only one index
is created on startup (the db raises an error that this index already
exists for other entities). Some generated SQL statements:
Hibernate: create index id_index on "customer" ("id")
Hibernate: create index id_index on "user" ("id")
2020-02-15 17:47:26,620 WARN o.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl - GenerationTarget encountered exception accepting command : Error executing DDL "create index id_index on "customer" ("id")" via JDBC Statement
org.postgresql.util.PSQLException: ERROR: relation "id_index" already exists
Any ideas on how to do this without too much code duplication?
Thanks
The only way I can see to do this - and it appears more trouble than it is worth to simply avoid placing an #Table annotation on each Entity - is to create a custom dialect and override the getIndexExporter() method:
public class MyPostgreSQLDialect extends PostgreSQLXXDialect{
#Override
public Exporter<Index> getIndexExporter() {
return new MyIndexExporter(this);
}
}
to return a customized Exporter, most likely extending org.hibernate.tool.schema.internal.StandardIndexExporter
public class MyIndexExporter extends StandardIndexExporter{
public MyIndexExporter(Dialect dialect){
super(dialect);
}
#Override
public String[] getSqlCreateStrings(Index index, Metadata metadata) {
//looks like you'd need to paste the whole code from superclass method
//and alter the index name accordingly
indexNameForCreation = index.getTable().getQualifiedTableName() +
"_" + index.getName();
//in the default implementation it is simply index.getName()
}
}
Alan Hay answer may work but it seems a bit of overengineering... So I decided to not use schema generation and use Liquibase instead, so I can have more control over the database.
Anyway, If anyone is having the same problem with schema generation, I tried with #Index (using eclipselink) and it worked, so this issue is only in Hibernate.

Annotate a Map in Hibernate

How to annotate a Map where keys are entity classes, and values normal java Objects (Boolean in my case) in an entity class?
I have two #Entity classes: Voter and Poll.
In the Poll class, I want to keep a Map< Voter,Boolean > of the Voters that can vote on this Poll. Boolean marks whether a Voter has voted or not. So the Mapping is Many-to-many in polls to voters.
I have classes:
#Enity
public class Voter {
...some attributes and their getters and setters
private List<Poll> polls;
private int voterId;
#Id
public int getVoterId() {
return voterId;
}
#ManyToMany(mappedBy="voters")
public List<Poll> getPolls() {
return polls;
}
..and setter.
}
#Enity
public class Poll {
...some attributes and their getters and setters
private Map<Voter,Boolean> voters;
#ManyToMany
#JoinColumn(referencedColumnName="voterId")
public Map<Voter,Boolean> getVoters() {
return voters;
}
..and setter.
}
This fails when run and causes AnnotationException.
I have seen annotation #MapKeyJoinColumn used, and tried with it as well (instaed of #JoinColumn), and failed. I haven't found an example like this (key of map an entity, value of map just an object) anywhere yet, so I basically used the try-fail way.
So the question is: what annotations should I put where?
For a map where the values are basic types (or Embeddable types) like Boolean, you need to use the #ElementCollection annotation. JPA will create a join table for the Map.
However, you cannot reference this collection table with a #ManyToMany annotated attribute in the Voter class. For this, you can add another Collection of Voter entities in the Poll class.
You can use #OneToMany and #ManyToMany annotations if you have an entity as the value type. Unfortunately, this is not applicable in your case.

How annotation mapping is done in java persistence?

We use annotations for mapping the entity class with the database table by simply specifying #Entity and more like #Id, table joins and many things. I do not know how these entity variables are getting mapped with database table. Can anyone give a short description for understanding.
Thanks :)
Well the idea is to translate your objects and their connections with other objects into a relational database. These two ways of representing data (objects defined by classes and in tables in a database) are not directly compatible and that is where a so called Object Relational Mapper framework comes into play.
So a class like
class MyObject
{
private String name;
private int age;
private String password;
// Getters and setters
}
Will translate into a database table containing a column name which is of type varchar, age of type int and password of type varchar.
Annotations in Java simply add additional information (so called meta data) to your class definitions, which can be read by any other class (e.g. JavaDoc) and in the case of the Java Persistence API will be used by an ORM framework like Hibernate to read additional information you need to translate your object into the database (your database table needs a primary id and some information - like what type of a relation an object has to another - can't be automatically determined by just looking at your class definition).
Annotations are very well explained here:
http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/
annotations are just metadata on a class, nothing magical. You can write your own annotations. Those annotations are given retention policies of runtime (which means you have access to that metadata at runtime). When you call persist etc the persistence provider iterates through the fields (java.lang.reflect.Field) in your class and checks what annotations are present to build up your SQL statement. Try writing your own annotation and doing something with it. It won't seem very magical after that.
in your case annotation working means mapping with tablename with entity class is look like as ....
#Entity
#Table(name = "CompanyUser")
public class CompanyUserCAB implements java.io.Serializable
{
private long companyUserID;
private int companyID;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "companyUserID")
public long getCompanyUserID()
{
return this.companyUserID;
}
public void setCompanyUserID(long companyUserID)
{
this.companyUserID = companyUserID;
}
#Column(name = "companyID")
public int getCompanyID()
{
return this.companyID;
}
public void setCompanyID(int companyID)
{
this.companyID = companyID;
}
}

Categories

Resources