Showing posts with label hibernate. Show all posts
Showing posts with label hibernate. Show all posts

Monday, May 6, 2019

Panache as a wrapper for Hibernate

https://quarkus.io/guides/hibernate-orm-panache-guide

https://developers.redhat.com/courses/quarkus/effective-data-hibernate-and-panache-quarkus/

The product seems very well conceived, it really streamlines your JPA code.

One more aspect where the Java world has completely screwed up, is the 20 different ways you can implement DB queries....
ah if only ORM had been embedded into the language from the beginning, we would be dealing with a single persistence framework.



Wednesday, April 11, 2018

Hibernate validator dependencies for unit testing

http://hibernate.org/validator/ home page of validation


at javax.validation.Validation$GenericBootstrapImpl.configure(Validation.java:271)
at javax.validation.Validation.buildDefaultValidatorFactory(Validation.java:110)
javax.validation.ValidationException: Unable to create a Configuration, because no Bean Validation provider could be found. Add a provider like Hibernate Validator (RI) to your classpath


I have this in my pom.xml

<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<scope>provided</scope>
</dependency>





Apparently I should add this implementation

<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.7.Final</version>
</dependency>


I do that, then I have :


java.lang.NoClassDefFoundError: javax/validation/ClockProvider
 at org.hibernate.validator.HibernateValidator.createGenericConfiguration(HibernateValidator.java:33)
 at javax.validation.Validation$GenericBootstrapImpl.configure(Validation.java:276)
 at javax.validation.Validation.buildDefaultValidatorFactory(Validation.java:110)

Caused by: java.lang.ClassNotFoundException: javax.validation.ClockProvider
 at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
 at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:357)





Then I add

<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.0.0.GA</version>
<scope>test</scope>
</dependency>




and I get

Caused by: java.lang.ClassNotFoundException: javax.validation.ParameterNameProvider


Here they say you should remove the validation-api : https://stackoverflow.com/questions/24652753/java-lang-noclassdeffounderror-javax-validation-parameternameprovider


I do this:


<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
<scope>test</scope>
</dependency>


now I get:



Caused by: javax.validation.ValidationException: HV000183: Unable to initialize 'javax.el.ExpressionFactory'. Check that you have the EL dependencies on the classpath, or use ParameterMessageInterpolator instead
 at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.buildExpressionFactory(ResourceBundleMessageInterpolator.java:123)
 at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.(ResourceBundleMessageInterpolator.java:47)
 at org.hibernate.validator.internal.engine.ConfigurationImpl.getDefaultMessageInterpolator(ConfigurationImpl.java:461)
 at org.hibernate.validator.internal.engine.ConfigurationImpl.getDefaultMessageInterpolatorConfiguredWithClassLoader(ConfigurationImpl.java:637)
 at org.hibernate.validator.internal.engine.ConfigurationImpl.getMessageInterpolator(ConfigurationImpl.java:388)
 at org.hibernate.validator.internal.engine.ValidatorFactoryImpl.(ValidatorFactoryImpl.java:179)
 at org.hibernate.validator.HibernateValidator.buildValidatorFactory(HibernateValidator.java:38)
 at org.hibernate.validator.internal.engine.ConfigurationImpl.buildValidatorFactory(ConfigurationImpl.java:355)
 at javax.validation.Validation.buildDefaultValidatorFactory(Validation.java:103)




So I add ( https://stackoverflow.com/questions/24386771/javax-validation-validationexception-hv000183-unable-to-load-javax-el-express )



<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>2.2.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>javax.el</artifactId>
<version>2.2.4</version>
<scope>test</scope>
</dependency>



and I get

java.lang.ClassNotFoundException: javax.el.ELManager


then I finally use

<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>3.0.0</version>
<scope>test</scope>
</dependency>


and it works!

once more, all you need is:

  <dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <scope>provided</scope>
  </dependency>

  <dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.0.7.Final</version>
    <scope>test</scope>
  </dependency>

  <dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>2.0.1.Final</version>
    <scope>test</scope>
  </dependency>

<dependency>
  <groupId>javax.el</groupId>
  <artifactId>javax.el-api</artifactId>
  <version>3.0.0</version>
    <scope>test</scope>
</dependency>

  <dependency>
    <groupId>org.glassfish.web</groupId>
    <artifactId>javax.el</artifactId>
    <version>2.2.4</version>
    <scope>test</scope>
  </dependency>
  















Saturday, November 18, 2017

JPA, Hibernate, Dali and the Metamodel

When building Query criterias, you want to avoid using the String "email" to identify an Entity field... the day you change the field "email" into "mailaddress", your code still compiles but breaks in PROD... ugly... unless you wrote tests... but I prefer when it breaks during compile!

So you must use https://docs.jboss.org/hibernate/entitymanager/3.5/reference/en/html/querycriteria.html "the static form of metamodel reference", that is using an automatically generated class

https://stackoverflow.com/questions/3037593/how-to-generate-jpa-2-0-metamodel

Example:

package org.pierre.calories.entities;

import java.io.Serializable;
import javax.persistence.*;
import java.math.BigDecimal;


/**
 * The persistent class for the USERS database table.
 * 
 */
@Entity
@Table(name="USERS")
@NamedQuery(name="User.findAll", query="SELECT u FROM User u")
public class User implements Serializable {
 private static final long serialVersionUID = 1L;

 @Id
 @GeneratedValue
 private String userid;

 private BigDecimal expectedcalperday;
 
 private String email;

 public String getEmail() {
  return email;
 }

 public void setEmail(String email) {
  this.email = email;
 }

 public User() {
 }

 public User(String userid, BigDecimal expectedcalperday) {
  super();
  this.userid = userid;
  this.expectedcalperday = expectedcalperday;
 }

 public String getUserid() {
  return this.userid;
 }

 public void setUserid(String userid) {
  this.userid = userid;
 }

 public BigDecimal getExpectedcalperday() {
  return this.expectedcalperday;
 }

 public void setExpectedcalperday(BigDecimal expectedcalperday) {
  this.expectedcalperday = expectedcalperday;
 }

}



and its metamodel

package org.pierre.calories.entities;

import java.math.BigDecimal;
import javax.annotation.Generated;
import javax.persistence.metamodel.SingularAttribute;
import javax.persistence.metamodel.StaticMetamodel;

@Generated(value="Dali", date="2017-11-18T11:02:45.198+0100")
@StaticMetamodel(User.class)
public class User_ {
 public static volatile SingularAttribute<User, String> userid;
 public static volatile SingularAttribute<User, BigDecimal> expectedcalperday;
 public static volatile SingularAttribute<User, String> email;
}


To achieve this in Eclipse: Project/Properties and then:





The multitude of very complicated options (in Maven for instance) to achieve the same EASY result is just one more evidence of the very pathetic state of IT in 2017.... a huge spread of technologies and product to achieve really basic results.... the notion of metadata associated to persistence was around already 25 years ago, it's sad to see that we still don't have proper engineering and consolidated practice.

At this point I can write my logic like this:

package org.pierre.calories.database;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;

import org.pierre.calories.entities.Meal;
import org.pierre.calories.entities.User;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;


@ApplicationScoped
public class CaloriesRepository {

    @Inject
    private EntityManager em;
    
    public Meal findMealById(Long id) {
        return em.find(Meal.class, id);
    }
    
    public User findUserById(Long id) {
        return em.find(User.class, id);
    }
        
    public User findUserByEmail(String email) {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<User> criteria = cb.createQuery(User.class);
        Root<User> rootUser = criteria.from(User.class);
        CriteriaQuery<User> select = criteria.select(rootUser);
//OLD SCHOOL  CriteriaQuery<User> emailresult = select.where(cb.equal(rootUser.get("email"), email));
        CriteriaQuery<User> emailresult = select.where(cb.equal(rootUser.get(User_.email), email));
        return em.createQuery(emailresult).getSingleResult();
    }  
    
}


Of course there are much easier ways to achieve the same result, like JPQL https://en.wikipedia.org/wiki/Java_Persistence_Query_Language




Tuesday, June 13, 2017

JPA, EclipseLink and Hibernate as a persistence provider

a customer was getting
 weblogic.management.DeploymentException: 

 java.lang.ClassCastException: org.eclipse.persistence.jpa.jpql.parser.NullExpression 
cannot be cast to org.eclipse.persistence.jpa.jpql.parser.IdentificationVariable
 at org.eclipse.persistence.internal.jpa.jpql.DeclarationResolver$DeclarationVisitor.visit(DeclarationResolver.java:626)
 at org.eclipse.persistence.jpa.jpql.parser.RangeVariableDeclaration.accept(RangeVariableDeclaration.java:98)
 at org.eclipse.persistence.internal.jpa.jpql.DeclarationResolver$DeclarationVisitor.visit(DeclarationResolver.java:577)
 at org.eclipse.persistence.jpa.jpql.parser.IdentificationVariableDeclaration.accept(IdentificationVariableDeclaration.java:71)
 at org.eclipse.persistence.internal.jpa.jpql.DeclarationResolver$DeclarationVisitor.visit(DeclarationResolver.java:566)


using eclipselink.jar version 2.5.2 as part of the WLS distribution.
he finally made it work by using
weblogic-application.xml :

<prefer-application-packages>
  <package-name>com.google.collections</package-name>
  <package-name>com.google.common</package-name>
  <package-name>org.hibernate.*</package-name>
  <package-name>javax.validation</package-name>
</prefer-application-packages>



change the pom.xml to get extra dependency
<dependency>
  <groupId>org.hibernate</groupId>
  <artifactId>hibernate-validator</artifactId>
  <version>5.3.5.Final</version>
</dependency>




and in persistence.xml
<provider>org.hibernate.ejb.HibernatePersistence</provider>





Friday, March 18, 2011

Hibernate Cascading on flushing




this snapshot (taken with YourKit profiler) shows the tremendous performance impact of cascading the flush to dependent objects - even if nothing has to be written to the DB.

Basically if you have
Employee {
String name;
Company company;
}

and you update/flush Employee, the blessed hibernate will try to flush also Company; And if Company contains other dependent objects, the process will go on forever and eat all your CPU.

CascadeType should be NONE by default.

As you can see here
http://www.docjar.com/docs/api/org/hibernate/event/def/AbstractFlushingEventListener.html

there are quite a lot of operations involved when persisting stuff.


So the message is: avoid as much as you can doing "find" operation in a transaction where you do updates (this will autoflush at every find). Also avoid cascading operations on dependent objects.

Thursday, March 17, 2011

hibernate DefaultAutoFlushEventListener.onAutoFlush


this explains very well

http://blog.xebia.com/2008/07/18/configuring-hibernate-and-spring-for-jta/

and

"The Session is sometimes flushed before query execution in order to ensure that queries never return stale state. This is the default flush mode. "


using FlushModeType.COMMIT
http://download.oracle.com/javaee/5/api/javax/persistence/EntityManager.html#setFlushMode%28javax.persistence.FlushModeType%29

improves a LOT performance, because flushing is an expensive operation.
But the result can be undetermined, and in fact my application now breaks because "find" queries don't find non-flushed entities:

see here

"If FlushModeType.COMMIT is set, the effect of updates made to entities in the persistence context upon queries is unspecified. "

:o))) I love working with unspecified products! Such a thrill!
These APIs were designed by lawyers.


Here it says explicitely:

Set flushes to occur at commit or before query execution. If
the flush mode is set to FlushModeType.COMMIT, changes
made during the transaction might not be visible in the
query execution results.


Friday, February 25, 2011

javax.persistence.PersistenceException: org.hibernate.PropertyValueException: not-null property references a null or transient value: bla

org.hibernate.PropertyValueException is a nice animal, containing a lot of useful info:

entityName
propertyName

so instead of doing yourself the validation on all the properties to be persisted, you can delegate Hibernate.

The problem with Hibernate is that it's a fail-fast validation: the first invalid property (null or referencing an non existing entity) will throw an exception.

If you want to capture ALL the validation errors, then you need to do it individually testing each property.

Thursday, February 24, 2011

Hibernate generating IDs from a Sequence

on the Entity:

@Id
@SequenceGenerator(name="PRODUCT_PROID_GENERATOR", sequenceName="PRO_ID_SEQ")
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="PRODUCT_PROID_GENERATOR")
@Column(name="PRO_ID", unique=true, nullable=false, precision=12)
private long proId;

and on the DB:

CREATE SEQUENCE PRO_ID_SEQ MINVALUE 1 START WITH 1 INCREMENT BY 1;



funnily the values assigned are:
1050
50
100

here a decent explanation about hilo :
https://forum.hibernate.org/viewtopic.php?f=9&t=1005635&view=next



so adding allocationSize=1 to @SequenceGenerator brings the behaviour back to normal