Spring, hibernate entity fields depending on profile - java

i have something like this:
#Entity
#Table(name = "schedules")
public class ScheduleDO {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
#Column(name = "begin_time", columnDefinition = "TIMESTAMP WITH TIME ZONE",
nullable = false)
private OffsetDateTime beginTime;
}
And i want to be able to change the "beginTime" variable anotation based on active profile. Something like this:
#Profile("dev")
#Column(name = "begin_time_dev", columnDefinition = "TIMESTAMP WITH TIME ZONE",
nullable = false)
#Profile("test")
#Column(name = "begin_time_test", columnDefinition = "TIMESTAMP WITH TIME ZONE",
nullable = false)
private OffsetDateTime beginTime;
is something like that possible?

Actually JPA/Hibernate know nothing about spring so profiles is out of their scope. Moreover entities are not beans so spring don't use them
The only solution I can see is to define a placeholder {profile_begin_time_test} and add an interceptor (see the example).
In the method
public String onPrepareStatement(String sql)
In the sql generated by hibernate replace the {profile_begin_time_test} placeholder with desired real column name. The placeholder replacement can be configured to use value based on spring profiles.

You could do this by creating a custom Hibernate UserType and registering it on your beginTime field via the Hibernate #Type annotation.
In your new UserType, you could then get the current profile from the Spring Environment to determine the target column name. You'll have to statically register the Environment in your application somehow first, as your UserType will have been instantiated by Hibernate and won't know about your Spring application context. All doable though!

I think that you could possibly :
1)Create two different fields and different setters.
2)Add all JPA annotations on method level rather than on fields.
3)Since spring 4.1 you can profile methods, so use profiles on setters.
The #Profile annotation may be used in any of the following ways: as a type-level annotation on any class directly or indirectly annotated with #Component, including #Configuration classes. As a meta-annotation, for the purpose of composing custom stereotype annotations. As a method-level annotation on any #Bean method
PROFILE DOCS

Related

when is a #Column annotation required for persistent properties of JPA classes?

In my JPA model I typically annotate each persistent class with #Entity and each persistent property with an appropriate annotation e.g. #Id, #Column, #ManyToOne, etc. A typical example is
#Entity
#Table(name = "files")
public class StoredFile {
#Id
#Type(type = "uuid-char")
private UUID id;
#Column(name = "file_name")
private String fileName;
// getters and setters omitted
}
I was looking at this example entity class and noticed that only the id field has a JPA annotation, i.e. there are no annotations specified for name or price.
Under what circumstances will a property of an #Entity be persisted if there are no annotations on the field/getter/setter?
You don't need to specify #Column annotation to persist a bean property.
#Column has to be used to specify a name of a table column. So if a naming strategy is used, you don't need to use #Column.
My advice is to always use #Column even if you don't need to specify a name.
#Column
private String fileName;
Also never mix fields and getters annotations.
Everything is primary for Hibernate.

Quarkus with Panache getting hibernate error HHH000183

I built an application with Quarkus and I'm using Hibernate with Panache for the models. Everything goes well, the application starts, but when I call a webservice to get a list using Panache functionalities (.listAll()), I get an empty list and I see the following message in the console:
HHH000183: no persistent classes found for query class: from com.myproject.model.TeamEntity
My models are defined with #Entity annotations that should allow Hibernate to find by itself the entity mappings. Here is an example with the Team model:
#Entity
#Table(name = "TEAM")
public class TeamEntity extends PanacheEntityBase {
#Id
#GeneratedValue(strategy = SEQUENCE, generator = "TEAM_SEQ_GEN")
#SequenceGenerator(name = "TEAM_SEQ_GEN", sequenceName = "TEAM_SEQ", allocationSize = 10)
#Column(name = "ID_TEAM", nullable = false)
private int id;
#Column(name = "NAME", nullable = false)
private String name;
...
}
I don't have any persistence.xml file in the project, only the application.properties linked with Quarkus. Here are the relevant properties extracted from mine:
quarkus.datasource.db-kind=oracle
quarkus.datasource.jdbc.url=jdbc:oracle:thin:/#MYWALLET
%dev.quarkus.datasource.jdbc.url=jdbc:oracle:thin:MYUSER/MYPASSWORD#localhost:1521/SAA
quarkus.datasource.jdbc.driver=oracle.jdbc.OracleDriver
quarkus.datasource.jdbc.min-size=2
quarkus.datasource.jdbc.max-size=10
quarkus.datasource.jdbc.new-connection-sql=alter session set current_schema=MYSCHEMA
quarkus.hibernate-orm.dialect=org.hibernate.dialect.Oracle12cDialect
Does someone know where the problem could come from ? Hibernate should detect entities with annotations and use them in queries automatically.
It came out that the problem was on Quarkus Datasource configuration in the application.properties file. More particularly from this specific line to define the schema used at first connection (I have to admit that was not good looking):
quarkus.datasource.jdbc.new-connection-sql=alter session set current_schema=MYSCHEMA
Replacing the line above with the following solved the problem:
quarkus.hibernate-orm.database.default-schema=MYSCHEMA
In conclusion, I think Hibernate cannot find / does not take the entities defined if this property is not defined, maybe because it makes some kind of detection beforehand. That's only a supposition, if someone knows more precisely how Hibernate works for that specific case, I would be very interested !

Removing duplication in Hibernate annotations

We are using Hibernate 3.6.x and Joda-time, persisting DateTime with a org.jadira.usertype.dateandtime.joda.PersistentDateTimeWithZone like so:
#Columns(columns = {
#Column(nullable = false, name = "requestedOn"),
#Column(nullable = false, name = "requestedOnTZ") })
#Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTimeWithZone")
private DateTime requestedOn;
Is there a way to hook into Hibernate in order to hide the annotations above behind one annotation, like:
#DateTimeWithZone(time = "requestedOn", zone = "requestedOnTZ")
private DateTime requestedOn;
?
I don't think you can. Those are standard annoatations that the API expects to find while processing your code (scanning for annotations in this case. You can hack your hibernate and modify it's annotation scanner to take into account a custom annotation you've made, but this will spell trouble later when you want to migrate to a newer version of Hibernate.

When should I use #Basic(optional = false) in JPA 2.0

I have a Inheritance with Single Table mapping in JPA, Say Class A and B extends some abstract entity, so I have to make columns from A & B nullable at DB end but if someone is trying to persist A then all fields of A should be not null and i want to enforce this by code.
Can I use following code to achieve this -
#Entity
#DiscriminatorValue("1")
public Class A extends SomeAbstractEntity{
#Basic(optional = false)
private String nameOfA;
}
I read this answer #Basic(optional = false) vs #Column(nullable = false) in JPA and thought this may be achievable but wanted to know what is the best way.
It's quite funny, but it looks like in this case (with single table inheritance) #Basic(optional = false) is not enforced by Hibernate (though in other cases it works as expected).
If so, the only option to enforce this rule is to use #NotNull constraint from JSR-303 Bean Validation. JSR-303 smoothly integrates with JPA 2.0, so that constraints are checked automatically when entities are persisted, see Hibernate Validator.

Create a custom JPA temporal annotation

I want some of mycoulmns in the JPA entity to take values from database during inserts/updates, i.e from Oracle sys_context, I believe JPA temporal annotation includes database generated timestamps during insert/updates, Is there any way I could create a custom annotation somewhat simailar to this or provide some default values during inserts/updates, can someone give few pointers if you faced this situation.
I want some of mycoulmns in the JPA entity to take values from database during inserts/updates
Configure the #Column to be not insertable and updatable and annotate the field with #Generated (Hibernate specific annotation). By doing so, Hibernate will fetch the value from the database after an insert, update. From the Reference Documentation:
2.4.3.5. Generated properties
Some properties are generated at
insert or update time by your
database. Hibernate can deal with such
properties and triggers a subsequent
select to read these properties.
#Entity
public class Antenna {
#Id public Integer id;
#Generated(GenerationTime.ALWAYS)
#Column(insertable = false, updatable = false)
public String longitude;
#Generated(GenerationTime.INSERT) #Column(insertable = false)
public String latitude;
}
Annotate your property as #Generated
You have to make sure your
insertability or updatability does not
conflict with the generation strategy
you have chosen. When
GenerationTime.INSERT is chosen, the
property must not contains insertable
columns, when GenerationTime.ALWAYS
is chosen, the property must not
contains insertable nor updatable
columns.
#Version properties cannot be
#Generated(INSERT) by design, it has
to be either NEVER or ALWAYS.

Categories

Resources