My Java application has become very slow due to the BLOB field that each entity has. This field is usually used to store a PDF file and whenever i have to list all the objects, it takes a considerable amount of time until the persistence provider can finish its job. I looked for answers on how to deal with such type of data, but some of them talk about storing the BLOB in a separate table and then using FetchType.LAZY. Is there any way to fetch this field only when needed without having to create another table? If not, is creating another table the most appropriate solution?
Entity Code
#Cache(alwaysRefresh = true)
public class ScdDocumento implements Serializable, MultipleSelector {
#Transient
public static final String QUERY_RELATORIO_DOC_LOC = "consultas/ctrl_docs/consulta_relatorio_doc_local.txt";
#Transient
public static final String QUERY_RELATORIO_DOC_GRUPO = "consultas/ctrl_docs/consulta_relatorio_doc_grupo.txt";
#Id
#Column(name = "nome", length = 50)
private String nome;
#Column(name = "revisao")
private int revisao;
#Column(name = "id_tipo")
private int id_tipo;
#Column(name = "situacao", length = 1)
private String situacao;
#Column(name = "doc_blob_nome", length = 50)
private String doc_blob_nome;
#Lob
#Basic(fetch = FetchType.LAZY)
#Column(name = "documento_blob", nullable = false)
private byte[] documento_blob; //The field that impacts the application perfomance
#Column(name = "abrangencia_geral")
private int abrangencia_geral;
#ManyToMany
#JoinTable(name = "SCD_DOC_GRUPO", joinColumns = {#JoinColumn(name = "id_doc")},
inverseJoinColumns = {#JoinColumn(name = "id_grupo")})
private Set<SosGrupo> grupos;
#ManyToOne
#JoinColumn(name = "id_tipo", insertable = false, updatable = false)
private ScdTipo tipo;
#ManyToMany
#JoinTable(name = "SCD_REFERENCIA", joinColumns = {#JoinColumn(name = "doc_pai")},
inverseJoinColumns = {#JoinColumn(name = "doc_filho")})
private Set<ScdDocumento> referencias;
#ManyToMany
#JoinTable(name = "SCD_REFERENCIA", joinColumns = {#JoinColumn(name = "doc_filho")},
inverseJoinColumns = {#JoinColumn(name = "doc_pai")})
private Set<ScdDocumento> referenciadoPor;
#ManyToMany
#JoinTable(name = "SCD_PALAVRA_REFERENCIA", joinColumns = {#JoinColumn(name = "documento")},
inverseJoinColumns = {#JoinColumn(name = "palavra")})
private Set<ScdPalavraChave> palavrasChaves;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "documento")
private Set<ScdOrdem> ordens;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "documento")
private Set<ScdArquivoOs> arquivosOs;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "documento")
private Set<ScdArquivoHistorico> arquivosHistorico;
#ManyToMany(cascade = {CascadeType.REFRESH, CascadeType.MERGE})
#JoinTable(name = "SCD_LOCAL_DOC", joinColumns = {#JoinColumn(name = "id_doc")},
inverseJoinColumns = {#JoinColumn(name = "id_local")})
private Set<ScdLocal> locais;
#Override
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public int getRevisao() {
return revisao;
}
public void setRevisao(int revisao) {
this.revisao = revisao;
}
public int getIdTipo() {
return id_tipo;
}
public void setIdTipo(int id_tipo) {
this.id_tipo = id_tipo;
}
public String getSituacao() {
return situacao;
}
public void setSituacao(String situacao) {
this.situacao = situacao;
}
public String getDocBlobNome() {
return doc_blob_nome;
}
public void setDocBlobNome(String doc_blob_nome) {
this.doc_blob_nome = doc_blob_nome;
}
public byte[] getDocumentoBlob() {
return documento_blob;
}
public void setDocumentoBlob(byte[] documento_blob) {
this.documento_blob = documento_blob;
}
public int getAbrangenciaGeral() {
return abrangencia_geral;
}
public void setAbrangenciaGeral(int abrangencia_geral) {
this.abrangencia_geral = abrangencia_geral;
}
public Set<SosGrupo> getGrupos() {
return grupos;
}
public void setGrupos(Set<SosGrupo> grupo) {
this.grupos = grupo;
}
public ScdTipo getTipo() {
return tipo;
}
public void setTipo(ScdTipo tipo) {
this.tipo = tipo;
}
public Set<ScdDocumento> getReferencias() {
return referencias;
}
public void setReferencias(Set<ScdDocumento> referencias) {
this.referencias = referencias;
}
public Set<ScdDocumento> getReferenciadoPor() {
return referenciadoPor;
}
public void setReferenciadoPor(Set<ScdDocumento> referenciadoPor) {
this.referenciadoPor = referenciadoPor;
}
public Set<ScdPalavraChave> getPalavrasChaves() {
return palavrasChaves;
}
public void setPalavrasChaves(Set<ScdPalavraChave> palavrasChaves) {
this.palavrasChaves = palavrasChaves;
}
public Set<ScdOrdem> getOrdens() {
return ordens;
}
public void setOrdens(Set<ScdOrdem> ordens) {
this.ordens = ordens;
}
public Set<ScdArquivoOs> getArquivosOs() {
return arquivosOs;
}
public void setArquivosOs(Set<ScdArquivoOs> arquivosOs) {
this.arquivosOs = arquivosOs;
}
public Set<ScdArquivoHistorico> getArquivosHistorico() {
return arquivosHistorico;
}
public void setArquivosHistorico(Set<ScdArquivoHistorico> arquivosHistorico) {
this.arquivosHistorico = arquivosHistorico;
}
public Set<ScdLocal> getLocais() {
return locais;
}
public void setLocais(Set<ScdLocal> locais) {
this.locais = locais;
}
#Override
public String getIdRef() {
return nome;
}
#Override
public String getDesc() {
return tipo.getNome();
}
}
Methods that are causing the problem
GUI
private void loadDocumentTable(String situacao) {
mapaDocumentos = new TreeMap<>();
modelDocumentos.setRowCount(0);
docdao.getCriteria("situacao", situacao).forEach((e) -> {
mapaDocumentos.put(e.getNome(), e);
});
mapaDocumentos.entrySet().forEach((e) -> {
String desc = e.getValue().getDocBlobNome();
modelDocumentos.addRow(new Object[]{e.getKey(), desc.substring(0, desc.length() - 3), e.getValue().getRevisao()});
});
}
Generic Dao
#Override
public List<T> getCriteria(String column, Object value){
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<T> cq = cb.createQuery(clazz);
Root<T> root = cq.from(clazz);
EntityType<T> ent = root.getModel();
cq.where(cb.equal(root.get(ent.getSingularAttribute(column)), value.toString()));
return em.createQuery(cq).getResultList();
}
Table Model
Persistence
Added this to my persistence.xml, but eclipselink still fetched the byte[] field eagerly.
Maven Plugin
<plugin>
<groupId>de.empulse.eclipselink</groupId>
<artifactId>staticweave-maven-plugin</artifactId>
<version>1.0.0</version>
<executions>
<execution>
<phase>process-classes</phase>
<goals>
<goal>weave</goal>
</goals>
<configuration>
<persistenceXMLLocation>META-INF/persistence.xml</persistenceXMLLocation>
<logLevel>FINE</logLevel>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.jpa</artifactId>
<version>2.5.2</version>
</dependency>
</dependencies>
</plugin>
Final Edit
The staticweave-maven-plugin actually worked, but I need to build the project everytime I change something in order for the performance to be boosted. This happens because the weaving is static, so it's applied at build time and not when running the project using the IDE.
JPA basics also allow specifying a fetch type of LAZY, which would prevent loading the BLOB until you access it in the entity. OneToOne, ManyToOne and basic mappings require byte code enhancement of your entities for EclipseLink to gain notification when you access a lazy attribute and load it, which is described here as weaving. This will ensure that it isn't loaded by default.
With the use of weaving, you can also use entity graphs to specify what is loaded and when. This can allow loading the blob in a single query with the rest of the entity when it is to be used, and exclude it by default elsewhere. See What is the diffenece between FETCH and LOAD for Entity graph of JPA? for info on load and fetch graphs.
Related
I have some tables :
PROFIL : id_profil, ...
EXPERIENCE : id_experience, id_profil#, ...
COMPETENCE_LEVEL : id_competence_level, level, ...
One PROFIL can have lot of EXPERIENCE and lot of COMPETENCE_LEVEL.
One EXPERIENCE can have lot of COMPETENCE_LEVEL.
One COMPETENCE_LEVEL concerns lot of EXPERIENCE.
So, for me, between EXPERIENCE and COMPETENCE_LEVEL, this is a (n-p) ManyToMany relation.
I tried:
PROFIL.java:
#Entity
#Table(name="profil")
public class Profil {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id_profil")
private Long idProfil;
public Profil() {
super();
}
public Long getIdProfil() {
return idProfil;
}
public void setIdProfil(Long idProfil) {
this.idProfil = idProfil;
}
#Override
public String toString() {
//[...]
}
}
EXPERIENCE.java:
#Entity
#Table(name="experience")
public class Experience {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id_experience")
private Long idExperience;
#ManyToOne
#JoinColumn(name="id_profil")
private Profil idProfil;
private List<CompetenceLevel> competenceLevels;
public Experience() {
super();
idProfil = new Profil();
}
public Long getIdExperience() {
return idExperience;
}
public void setIdExperience(Long idExperience) {
this.idExperience = idExperience;
}
public Profil getIdProfil() {
return idProfil;
}
public void setIdProfil(Profil idProfil) {
this.idProfil = idProfil;
}
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "experience_competence_level", joinColumns = #JoinColumn(name = "id_experience", referencedColumnName = "id_experience"), inverseJoinColumns = #JoinColumn(name = "id_competence_level", referencedColumnName = "id_competence_level"))
public List<CompetenceLevel> getCompetenceLevels() {
return competenceLevels;
}
public void setCompetenceLevels(List<CompetenceLevel> competenceLevels) {
this.competenceLevels = competenceLevels;
}
#Override
public String toString() {
// [...]
}
}
COMPETENCE_LEVEL.java:
#Entity
#Table(name="competence_level")
public class CompetenceLevel {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id_competence_level")
private Long idCompetenceLevel;
#OneToOne
#JoinColumn(name="id_level")
private Level level;
#OneToOne
#JoinColumn(name="id_profil")
private Profil profil;
private List<Experience> experiences;
public CompetenceLevel() {
super();
}
public Long getIdCompetenceLevel() {
return idCompetenceLevel;
}
public void setIdCompetenceLevel(Long idCompetenceLevel) {
this.idCompetenceLevel = idCompetenceLevel;
}
public Level getLevel() {
return level;
}
public void setLevel(Level level) {
this.level = level;
}
public Profil getProfil() {
return profil;
}
public void setProfil(Profil profil) {
this.profil = profil;
}
#ManyToMany(mappedBy = "competenceLevels")
public List<Experience> getExperiences() {
return experiences;
}
public void setExperiences(List<Experience> experiences) {
this.experiences = experiences;
}
#Override
public String toString() {
// [...]
}
}
So, I have this error :
org.hibernate.MappingException: Could not determine type for: java.util.List, at table: competence_level, for columns: [org.hibernate.mapping.Column(experiences)]
I don't understand why. I follow this tuto : https://hellokoding.com/jpa-many-to-many-relationship-mapping-example-with-spring-boot-maven-and-mysql/
Do you have an idea ? Thanks.
The reason is simply: don't mix field and method annotations in the same persistent class.
Hibernate generates an unclear error here. It is very hard to figure out the reason of the error, if you don't face it before.
In your code, you are mixing field access and property access. See this answer.
I would prefer using only one of the possibilities. I use field annotations, like you did for idProfil.
In the book "Professional Java for Web Applications" by Nicholas S. Williams (very, very good) I found this:
You should never mix JPA property annotations and JPA field
annotations in the same entity. Doing so results in unspecified
behaviour and is very likely to cause errors.
And just for clearness, I wouldn't write this
#ManyToOne
#JoinColumn(name="id_profil")
private Profil idProfil;
// better:
// private Profil profil;
I'm working with Spring, hibernate and MySql but I have some problem with seralization of query result.
First in my entity I added #JsonManagedReference on Set structure (#OneToMany side) and #JsonBackReference on single object reference (#ManyToOne side) and it works but I wasn't be able to retrieve all needed information (for example #ManyToOne reference).
So i swapping #JsonBackReference on set structure and #JsonManagedReference on single object but I retrieve
No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: com.model.tablesField.TableUI["data"]->java.util.ArrayList[0]->com.domain.Car["carType"]->com.domain.CarType_$$_jvst744_f["handler"])
I tried also with #JsonIgnore on Set structure but it doesn't work for the same issues.
This is my spring configuration
private Properties getHibernateProperties() {
Properties properties = new Properties();
properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
// properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
properties.put(PROPERTY_NAME_HIBERNATE_FORMAT_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_FORMAT_SQL));
properties.put("hibernate.enable_lazy_load_no_trans",true);
return properties;
and this is part of one of my several entities:
/**
* Car generated by hbm2java
*/
#Entity
#Table(name = "car", catalog = "ATS")
public class Car implements java.io.Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private Integer idCar;
#JsonManagedReference
private CarType carType;
#JsonManagedReference
private Fleet fleet;
private String id;
private int initialKm;
private String carChassis;
private String note;
#JsonBackReference
private Set<Acquisition> acquisitions = new HashSet<Acquisition>(0);
public Car() {
}
public Car(CarType carType, Fleet fleet, int initialKm, String carChassis) {
this.carType = carType;
this.fleet = fleet;
this.initialKm = initialKm;
this.carChassis = carChassis;
}
public Car(CarType carType, Fleet fleet, String id, int initialKm, String carChassis, String note,
Set<Acquisition> acquisitions) {
this.carType = carType;
this.fleet = fleet;
this.id = id;
this.initialKm = initialKm;
this.carChassis = carChassis;
this.note = note;
this.acquisitions = acquisitions;
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id_car", unique = true, nullable = false)
public Integer getIdCar() {
return this.idCar;
}
public void setIdCar(Integer idCar) {
this.idCar = idCar;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_carType", nullable = false)
public CarType getCarType() {
return this.carType;
}
public void setCarType(CarType carType) {
this.carType = carType;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_fleet", nullable = false)
public Fleet getFleet() {
return this.fleet;
}
public void setFleet(Fleet fleet) {
this.fleet = fleet;
}
#Column(name = "id", length = 5)
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
#Column(name = "initialKm", nullable = false)
public int getInitialKm() {
return this.initialKm;
}
public void setInitialKm(int initialKm) {
this.initialKm = initialKm;
}
#Column(name = "carChassis", nullable = false, length = 20)
public String getCarChassis() {
return this.carChassis;
}
public void setCarChassis(String carChassis) {
this.carChassis = carChassis;
}
#Column(name = "note", length = 100)
public String getNote() {
return this.note;
}
public void setNote(String note) {
this.note = note;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "car")
public Set<Acquisition> getAcquisitions() {
return this.acquisitions;
}
public void setAcquisitions(Set<Acquisition> acquisitions) {
this.acquisitions = acquisitions;
}
}
one method that uses the query:
#Override
#RequestMapping(value = { "/cars/{idFleet}"}, method = RequestMethod.GET)
public #ResponseBody TableUI getCars(#PathVariable int idFleet) {
TableUI ajaxCall=new TableUI();
try {
ajaxCall.setData(fleetAndCarService.findCarsByIdFleet(idFleet));
return ajaxCall;
} catch (QueryException e) {
ErrorResponse errorResponse= ErrorResponseBuilder.buildErrorResponse(e);
LOG.error("Threw exception in FleetAndCarControllerImpl::addCar :" + errorResponse.getStacktrace());
return ajaxCall;
}
}
two class for the query:
public interface DefRdiRepository extends JpaRepository<DefRdi, Integer>{
//#Query("SELECT CASE WHEN COUNT(c) > 0 THEN true ELSE false END FROM DefRdi c WHERE c.parName = ?1 AND c.description= ?2")
//Boolean existsByParNameAndDescription(String parName, String description);
//Query method of spring, I put findBy and then the key of research
DefRdi findByParNameAndDescription(String parName, String description);
}
public interface CarRepository extends JpaRepository<Car, Integer>, CarRepositoryCustom {
//Query method of spring, I put findBy and then the key of research
List<Car> findByFleetIdFleet(int idFleet);
}
Where is my error? I don't want Set object but only the single reference. The problem is only when I serialize. Thanks
UPDATE:
I use #JSonIgnore on all set collectionts and Eager instead lazy ad all works fine, but is there a way to retrieve all the information only when I want, for example having two different query?
So it doesn't work
#Override
#Transactional
public List<Car> findByFleetIdFleet(int idFleet) {
List<Car> carList= carRepository.findByFleetIdFleet(idFleet);
for (Car car:carList){
Hibernate.initialize(car.getCarType());
Hibernate.initialize(car.getFleet());
}
return carList;
// return carRepository.findByFleetIdFleet(idFleet);
}
All collections need to be fetched eagerly when loading them from data base, in order to get serialized by Spring. Make sure you fetch them eagerly (e.g. FetchMode.JOIN). You could also swap #JsonManagedReference from wanted fields with #JsonIgnore to black listed fields, Spring automatically serialises every field without annotation.
Update:
Changing the data repository to something like that should work, I am not sure it compiles, but I think you will get the point:
#EntityGraph(value = "some.entity.graph", type = EntityGraph.EntityGraphType.FETCH)
#Query(
value = "SELECT c FROM Car c INNER JOIN FETCH c.acquisitions WHERE c.id = :idFleet"
)
public interface CarRepository extends JpaRepository<Car, Integer>, CarRepositoryCustom {
//Query method of spring, I put findBy and then the key of research
List<Car> findByFleetIdFleet(int idFleet);
}
For more information look at this post and read the official documentation.
Workaround:
There seems to be a workaround, however fetching those collections eager like shown above should have a positive performance impact, since there is no need for loading proxies afterwards. Also no open transactions are needed at controller level.
This question already has answers here:
Using generics in Spring Data JPA repositories
(3 answers)
Closed 4 years ago.
I'm trying to do some basic database operations using a generic repository in Spring Data JPA. However, I keep running into an IllegalArgumentException "Not an managed type: " + whatever class/interface I have my parameter extend.
GenericRepository.java
#Transactional
public interface GenericRepository<T> extends PagingAndSortingRepository<T, Integer> {
#Query("SELECT g "
+ "FROM " + "#{#entityName}" + " g "
+ "WHERE g.#{#entityName}Id = ?1"
)
public T findById(int Id);
For example, the above complains about class Object, whereas using GenericRepository (a marker interface I was trying to use) it'll complain about interface DatabaseDerived being not a managed type.
I'm simply using #SpringBootApplication for most of my setup, and the answers I've been able to find for this problem either definitely don't work in my case or I can't seem to figure out how to apply them to my setup or I just plain don't understand them. I would be grateful if someone could point me to a useful tutorial (couldn't find one on Google) or walk me through how to get this working with my setup.
Application.java
#SpringBootApplication
#ComponentScan("radius.hibernate")
public class Application {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>annonymized</groupId>
<artifactId>radius.hibernate</artifactId>
<version>0.1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.6.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.6.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate4</artifactId>
<version>2.6.2</version>
</dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.10</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
</dependency>
</dependencies>
<properties>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Adjuster.java
/**
* Adjuster generated by hbm2java
*/
#Entity(name = "adjuster")
#Table(name = "Adjuster", schema = "dbo", catalog = "annonymized")
public class Adjuster implements java.io.Serializable, DatabaseDerived {
private int adjusterId;
private EagleUsers eagleUsersBySupervisorId;
private EagleUsers eagleUsersByUserId;
private boolean isW2;
private boolean autoAssign;
private boolean active;
private boolean isRecordDeleted;
private Set<AdjusterSoftware> adjusterSoftwares = new HashSet<AdjusterSoftware>(0);
private Set<BankInvoiceCorrection> bankInvoiceCorrectionsForOldAdjusterId = new HashSet<BankInvoiceCorrection>(0);
private Set<BankAdjuster> bankAdjusters = new HashSet<BankAdjuster>(0);
private Set<SymbilityAdjuster> symbilityAdjusters = new HashSet<SymbilityAdjuster>(0);
private AdjusterCompensation adjusterCompensation;
private AdjusterContact adjusterContact;
private Set<AdjusterClaimType> adjusterClaimTypes = new HashSet<AdjusterClaimType>(0);
private Set<AdjusterClientExclude> adjusterClientExcludes = new HashSet<AdjusterClientExclude>(0);
private Set<AdjusterEquipment> adjusterEquipments = new HashSet<AdjusterEquipment>(0);
private Set<ClaimAdjuster> claimAdjusters = new HashSet<ClaimAdjuster>(0);
private Set<ClaimReport> claimReports = new HashSet<ClaimReport>(0);
private Set<Invoice> invoices = new HashSet<Invoice>(0);
private Set<LicenseAdjuster> licenseAdjusters = new HashSet<LicenseAdjuster>(0);
private Set<AdjusterClientContactExclude> adjusterClientContactExcludes = new HashSet<AdjusterClientContactExclude>(
0);
private Set<BankInvoiceCorrection> bankInvoiceCorrectionsForNewAdjusterId = new HashSet<BankInvoiceCorrection>(0);
private AdjusterAutoAssign adjusterAutoAssign;
private Set<AdjusterLossType> adjusterLossTypes = new HashSet<AdjusterLossType>(0);
public Adjuster() {
}
public Adjuster(int adjusterId, EagleUsers eagleUsersBySupervisorId, EagleUsers eagleUsersByUserId, boolean isW2,
boolean autoAssign, boolean active, boolean isRecordDeleted) {
this.adjusterId = adjusterId;
this.eagleUsersBySupervisorId = eagleUsersBySupervisorId;
this.eagleUsersByUserId = eagleUsersByUserId;
this.isW2 = isW2;
this.autoAssign = autoAssign;
this.active = active;
this.isRecordDeleted = isRecordDeleted;
}
public Adjuster(int adjusterId, EagleUsers eagleUsersBySupervisorId, EagleUsers eagleUsersByUserId, boolean isW2,
boolean autoAssign, boolean active, boolean isRecordDeleted, Set<AdjusterSoftware> adjusterSoftwares,
Set<BankInvoiceCorrection> bankInvoiceCorrectionsForOldAdjusterId, Set<BankAdjuster> bankAdjusters,
Set<SymbilityAdjuster> symbilityAdjusters, AdjusterCompensation adjusterCompensation,
AdjusterContact adjusterContact, Set<AdjusterClaimType> adjusterClaimTypes,
Set<AdjusterClientExclude> adjusterClientExcludes, Set<AdjusterEquipment> adjusterEquipments,
Set<ClaimAdjuster> claimAdjusters, Set<ClaimReport> claimReports, Set<Invoice> invoices,
Set<LicenseAdjuster> licenseAdjusters, Set<AdjusterClientContactExclude> adjusterClientContactExcludes,
Set<BankInvoiceCorrection> bankInvoiceCorrectionsForNewAdjusterId, AdjusterAutoAssign adjusterAutoAssign,
Set<AdjusterLossType> adjusterLossTypes) {
this.adjusterId = adjusterId;
this.eagleUsersBySupervisorId = eagleUsersBySupervisorId;
this.eagleUsersByUserId = eagleUsersByUserId;
this.isW2 = isW2;
this.autoAssign = autoAssign;
this.active = active;
this.isRecordDeleted = isRecordDeleted;
this.adjusterSoftwares = adjusterSoftwares;
this.bankInvoiceCorrectionsForOldAdjusterId = bankInvoiceCorrectionsForOldAdjusterId;
this.bankAdjusters = bankAdjusters;
this.symbilityAdjusters = symbilityAdjusters;
this.adjusterCompensation = adjusterCompensation;
this.adjusterContact = adjusterContact;
this.adjusterClaimTypes = adjusterClaimTypes;
this.adjusterClientExcludes = adjusterClientExcludes;
this.adjusterEquipments = adjusterEquipments;
this.claimAdjusters = claimAdjusters;
this.claimReports = claimReports;
this.invoices = invoices;
this.licenseAdjusters = licenseAdjusters;
this.adjusterClientContactExcludes = adjusterClientContactExcludes;
this.bankInvoiceCorrectionsForNewAdjusterId = bankInvoiceCorrectionsForNewAdjusterId;
this.adjusterAutoAssign = adjusterAutoAssign;
this.adjusterLossTypes = adjusterLossTypes;
}
#Id
#Column(name = "AdjusterId", unique = true, nullable = false)
public int getAdjusterId() {
return this.adjusterId;
}
public void setAdjusterId(int adjusterId) {
this.adjusterId = adjusterId;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "SupervisorId", nullable = false)
public EagleUsers getEagleUsersBySupervisorId() {
return this.eagleUsersBySupervisorId;
}
public void setEagleUsersBySupervisorId(EagleUsers eagleUsersBySupervisorId) {
this.eagleUsersBySupervisorId = eagleUsersBySupervisorId;
}
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "UserId", nullable = false)
public EagleUsers getEagleUsersByUserId() {
return this.eagleUsersByUserId;
}
public void setEagleUsersByUserId(EagleUsers eagleUsersByUserId) {
this.eagleUsersByUserId = eagleUsersByUserId;
}
#Column(name = "IsW2", nullable = false)
public boolean isIsW2() {
return this.isW2;
}
public void setIsW2(boolean isW2) {
this.isW2 = isW2;
}
#Column(name = "AutoAssign", nullable = false)
public boolean isAutoAssign() {
return this.autoAssign;
}
public void setAutoAssign(boolean autoAssign) {
this.autoAssign = autoAssign;
}
#Column(name = "Active", nullable = false)
public boolean isActive() {
return this.active;
}
public void setActive(boolean active) {
this.active = active;
}
#Column(name = "IsRecordDeleted", nullable = false)
public boolean isIsRecordDeleted() {
return this.isRecordDeleted;
}
public void setIsRecordDeleted(boolean isRecordDeleted) {
this.isRecordDeleted = isRecordDeleted;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "adjuster", cascade = CascadeType.REMOVE)
public Set<AdjusterSoftware> getAdjusterSoftwares() {
return this.adjusterSoftwares;
}
public void setAdjusterSoftwares(Set<AdjusterSoftware> adjusterSoftwares) {
this.adjusterSoftwares = adjusterSoftwares;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "adjusterByOldAdjusterId")
public Set<BankInvoiceCorrection> getBankInvoiceCorrectionsForOldAdjusterId() {
return this.bankInvoiceCorrectionsForOldAdjusterId;
}
public void setBankInvoiceCorrectionsForOldAdjusterId(
Set<BankInvoiceCorrection> bankInvoiceCorrectionsForOldAdjusterId) {
this.bankInvoiceCorrectionsForOldAdjusterId = bankInvoiceCorrectionsForOldAdjusterId;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "adjuster", cascade = CascadeType.REMOVE)
public Set<BankAdjuster> getBankAdjusters() {
return this.bankAdjusters;
}
public void setBankAdjusters(Set<BankAdjuster> bankAdjusters) {
this.bankAdjusters = bankAdjusters;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "adjuster", cascade = CascadeType.REMOVE)
public Set<SymbilityAdjuster> getSymbilityAdjusters() {
return this.symbilityAdjusters;
}
public void setSymbilityAdjusters(Set<SymbilityAdjuster> symbilityAdjusters) {
this.symbilityAdjusters = symbilityAdjusters;
}
#OneToOne(fetch = FetchType.LAZY, mappedBy = "adjuster", optional = false)
public AdjusterCompensation getAdjusterCompensation() {
return this.adjusterCompensation;
}
public void setAdjusterCompensation(AdjusterCompensation adjusterCompensation) {
this.adjusterCompensation = adjusterCompensation;
}
#OneToOne(fetch = FetchType.LAZY, mappedBy = "adjuster")
public AdjusterContact getAdjusterContact() {
return this.adjusterContact;
}
public void setAdjusterContact(AdjusterContact adjusterContact) {
this.adjusterContact = adjusterContact;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "adjuster", cascade = CascadeType.REMOVE)
public Set<AdjusterClaimType> getAdjusterClaimTypes() {
return this.adjusterClaimTypes;
}
public void setAdjusterClaimTypes(Set<AdjusterClaimType> adjusterClaimTypes) {
this.adjusterClaimTypes = adjusterClaimTypes;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "adjuster", cascade = CascadeType.REMOVE)
public Set<AdjusterClientExclude> getAdjusterClientExcludes() {
return this.adjusterClientExcludes;
}
public void setAdjusterClientExcludes(Set<AdjusterClientExclude> adjusterClientExcludes) {
this.adjusterClientExcludes = adjusterClientExcludes;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "adjuster", cascade = CascadeType.REMOVE)
public Set<AdjusterEquipment> getAdjusterEquipments() {
return this.adjusterEquipments;
}
public void setAdjusterEquipments(Set<AdjusterEquipment> adjusterEquipments) {
this.adjusterEquipments = adjusterEquipments;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "adjuster", cascade = CascadeType.REMOVE)
public Set<ClaimAdjuster> getClaimAdjusters() {
return this.claimAdjusters;
}
public void setClaimAdjusters(Set<ClaimAdjuster> claimAdjusters) {
this.claimAdjusters = claimAdjusters;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "adjuster", cascade = CascadeType.REMOVE)
public Set<ClaimReport> getClaimReports() {
return this.claimReports;
}
public void setClaimReports(Set<ClaimReport> claimReports) {
this.claimReports = claimReports;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "adjuster", cascade = CascadeType.REMOVE)
public Set<Invoice> getInvoices() {
return this.invoices;
}
public void setInvoices(Set<Invoice> invoices) {
this.invoices = invoices;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "adjuster", cascade = CascadeType.REMOVE)
public Set<LicenseAdjuster> getLicenseAdjusters() {
return this.licenseAdjusters;
}
public void setLicenseAdjusters(Set<LicenseAdjuster> licenseAdjusters) {
this.licenseAdjusters = licenseAdjusters;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "adjuster", cascade = CascadeType.REMOVE)
public Set<AdjusterClientContactExclude> getAdjusterClientContactExcludes() {
return this.adjusterClientContactExcludes;
}
public void setAdjusterClientContactExcludes(Set<AdjusterClientContactExclude> adjusterClientContactExcludes) {
this.adjusterClientContactExcludes = adjusterClientContactExcludes;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "adjusterByNewAdjusterId")
public Set<BankInvoiceCorrection> getBankInvoiceCorrectionsForNewAdjusterId() {
return this.bankInvoiceCorrectionsForNewAdjusterId;
}
public void setBankInvoiceCorrectionsForNewAdjusterId(
Set<BankInvoiceCorrection> bankInvoiceCorrectionsForNewAdjusterId) {
this.bankInvoiceCorrectionsForNewAdjusterId = bankInvoiceCorrectionsForNewAdjusterId;
}
#OneToOne(fetch = FetchType.LAZY, mappedBy = "adjuster", optional = false)
public AdjusterAutoAssign getAdjusterAutoAssign() {
return this.adjusterAutoAssign;
}
public void setAdjusterAutoAssign(AdjusterAutoAssign adjusterAutoAssign) {
this.adjusterAutoAssign = adjusterAutoAssign;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "adjuster", cascade = CascadeType.REMOVE)
public Set<AdjusterLossType> getAdjusterLossTypes() {
return this.adjusterLossTypes;
}
public void setAdjusterLossTypes(Set<AdjusterLossType> adjusterLossTypes) {
this.adjusterLossTypes = adjusterLossTypes;
}
#Override
public Integer getId() {
return getAdjusterId();
}
#Override
public void setId(Integer id) {
setAdjusterId(id);
}
}
HelloController.java
#Autowired
#RequestMapping("/testGeneric")
public #ResponseBody String indexTest6(GenericRepository2<Adjuster, Integer> genericDao) throws JsonProcessingException {
Adjuster adjuster = (Adjuster) genericDao.findById(5567);
ObjectMapper mapper = new ObjectMapper();
Hibernate4Module module = new Hibernate4Module();
mapper.registerModule(module);
String result = mapper.writeValueAsString(adjuster);
return result;
}
That's not how it works.
You have to provide a repository interface with a concrete class for Spring Data to generate the implementation.
Like this:
public interface AdjusterRepository extends PagingAndSortingRepository<Adjuster, Long> {
#Query("SELECT g " // Don't know what this is doing
+ "FROM " + "#{#entityName}" + " g "
+ "WHERE g.#{#entityName}Id = ?1"
)
public Adjuster findById(long id);
}
In your case, I see you try to reuse your custom query for different classes. But Spring will pick up your GenericRepository and won't know what to do.
The correct approach is to mark this GenericRepositoy as #NoRepositoryBean so Spring doesn't try to instantiate it at runtime, which is the cause of your error.
So you can do this:
#NoRepositoryBean
public interface GenericRepository<T> extends PagingAndSortingRepository<T, Long> {
#Query("SELECT g " // Don't know what this is doing
+ "FROM " + "#{#entityName}" + " g "
+ "WHERE g.#{#entityName}Id = ?1"
)
public T findById(T id);
}
public interface AdjusterRepository extends GenericRepository<Adjuster> {
// will inherit from GenericRepository
}
By doing this, Spring will ignore the GenericRepository, avoiding you error, and create a concrete implementation only for AdjusterRepository, and any others that you subclass from GenericRepository.
I didn't test this code, there may be some typos. I recommend reading this section from the Spring Data reference: Defining repository interfaces
I'm getting this errors when trying to create relation between 2 entities, this time i'm doing this in different way - passing JSON with 2 object into helper class and then getting those object and persisting them, one by one and setting the relation. When i remove setters of relation : 1. newPerson.setKoordynator(koordynatorzyPraktykEntity);
2.koordynatorzyPraktykEntity.setKoordynatorByIdOsoby(newPerson);
then it is persisting both entities without a problem, with setters only first one (KoordynatorzyPraktykEntity) is persisted (idKoordynatora = 1, idOsoby =0, test = test )
Here is the important part of error from POSTMAN ( full log http://pastebin.com/SRmnPMBH )
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist: praktyki.core.entities.KoordynatorzyPraktykEntity; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: praktyki.core.entities.KoordynatorzyPraktykEntity
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:978)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
javax.servlet.http.HttpServlet.service(HttpServlet.java:644)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
KoordynatorzyEntity:
#Entity
#Table(name = "koordynatorzy_praktyk", schema = "public", catalog = "praktykidb")
public class KoordynatorzyPraktykEntity {
private int idKoordynatoraPraktyk;
private int idOsoby;
private String doTestow;
private OsobyEntity koordynatorByIdOsoby;
private Collection<KoordynatorzyKierunkowiEntity> koordynatorzyByIdKierunku;
#Id
#GeneratedValue
#Column(name = "id_koordynatora_praktyk")
public int getIdKoordynatoraPraktyk() {
return idKoordynatoraPraktyk;
}
public void setIdKoordynatoraPraktyk(int idKoordynatoraPraktyk) {
this.idKoordynatoraPraktyk = idKoordynatoraPraktyk;
}
#Basic
#Column(name = "id_osoby")
public int getIdOsoby() {
return idOsoby;
}
public void setIdOsoby(int idOsoby) {
this.idOsoby = idOsoby;
}
/*
STUFF
*/
#JsonIgnore
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "id_osoby", referencedColumnName = "id_osoby", insertable = false , updatable = false)
public OsobyEntity getKoordynatorByIdOsoby() {
return koordynatorByIdOsoby;
}
public void setKoordynatorByIdOsoby(OsobyEntity koordynatorByIdOsoby) {
this.koordynatorByIdOsoby = koordynatorByIdOsoby;
}
#JsonIgnore
#OneToMany(mappedBy = "koordynatorzyByIdKierunku", cascade = CascadeType.ALL)
#LazyCollection(LazyCollectionOption.FALSE)
public Collection<KoordynatorzyKierunkowiEntity> getKoordynatorzyByIdKierunku() {
return koordynatorzyByIdKierunku;
}
public void setKoordynatorzyByIdKierunku(Collection<KoordynatorzyKierunkowiEntity> koordynatorzyByIdKierunku) {
this.koordynatorzyByIdKierunku = koordynatorzyByIdKierunku;
}
OsobyEntity:
#Entity
#Table(name = "osoby", schema = "public", catalog = "praktykidb")
public class OsobyEntity {
private int idOsoby;
private String tytulZawodowy;
private String imie;
private String nazwisko;
private String email;
private String telefonKomorkowy;
private String telefonStacjonarny;
private KoordynatorzyPraktykEntity koordynator;
#Id
#GeneratedValue
#Column(name = "id_osoby")
public int getIdOsoby() {
return idOsoby;
}
public void setIdOsoby(int idOsoby) {
this.idOsoby = idOsoby;
}
/*
STUFF
*/
#OneToOne(mappedBy = "koordynatorByIdOsoby", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
public KoordynatorzyPraktykEntity getKoordynator() {
return koordynator;
}
public void setKoordynator(KoordynatorzyPraktykEntity koordynator) {
this.koordynator = koordynator;
}
KoordynatorzyPraktykService :
public class KoordynatorzyPraktykService implements iKoordynatorzyPraktykService {
#Autowired
private iKoordynatorzyPraktykDAO ikoordynatorzyPraktykDAO;
#Autowired
private iOsobyDAO iosobyDAO;
#Override
public KoordynatorzyPraktykEntity addCoordinator(KoordynatorzyPraktykEntity koordynatorzyPraktykEntity) {
return ikoordynatorzyPraktykDAO.addCoordinator(koordynatorzyPraktykEntity);
}
/*
STUFF
*/
#Override
public OsobyEntity addPerson(OsobyEntity osobyEntity, KoordynatorzyPraktykEntity koordynatorzyPraktykEntity) {
OsobyEntity newPerson = iosobyDAO.addPerson(osobyEntity);
newPerson.setKoordynator(koordynatorzyPraktykEntity);
System.out.println(koordynatorzyPraktykEntity.toString()); //shows idKoordynatora: 1 idOsoby: 0 test: test
System.out.println(newPerson.toString()); //shows idOsoby: 32768 imie: Tomasz nazwisko: Potempa
int idOsoby = newPerson.getIdOsoby();
koordynatorzyPraktykEntity.setIdOsoby(idOsoby);
System.out.println(koordynatorzyPraktykEntity.toString()); //shows idKoordynatora: 1 idOsoby: 32768 test: test
koordynatorzyPraktykEntity.setKoordynatorByIdOsoby(newPerson);
return newPerson;
}
Both DAOs have em.persist(entity)
and POST of KoordynatorzyPraktykController:
#RequestMapping(method = RequestMethod.POST)
public ResponseEntity<KoordynatorzyPraktykEntity> addCoordinator(#RequestBody Koordynator newCoordinator) {
KoordynatorzyPraktykEntity addCoordinator = ikoordynatorzyPraktykService.addCoordinator(newCoordinator.getKoordynator());
OsobyEntity addPerson = ikoordynatorzyPraktykService.addPerson(newCoordinator.getOsoba(), addCoordinator);
if (addCoordinator !=null && addPerson !=null) {
return new ResponseEntity<KoordynatorzyPraktykEntity>(addCoordinator, HttpStatus.OK);
}
else {
return new ResponseEntity<KoordynatorzyPraktykEntity>(HttpStatus.NOT_FOUND);
}
}
Helper Class Koordynator:
public class Koordynator {
private KoordynatorzyPraktykEntity koordynator;
private OsobyEntity osoba;
public KoordynatorzyPraktykEntity getKoordynator() {
return koordynator;
}
public void setKoordynator(KoordynatorzyPraktykEntity koordynator) {
this.koordynator = koordynator;
}
public OsobyEntity getOsoba() {
return osoba;
}
public void setOsoba(OsobyEntity osoba) {
this.osoba = osoba;
}
}
and this is parsed JSON into controller through POSTMAN
{
"koordynator":
{
"doTestow" : "test"
},
"osoba":
{
"tytulZawodowy" : "inzynier",
"imie" : "Tomasz",
"nazwisko" : "Potempa",
"email" : "tp#tp.pl",
"telefonKomorkowy" : "124675484",
"telefonStacjonarny" : "654786484"
}
}
Only way I got it work
Class A:
#OneToMany(cascade = CascadeType.MERGE)
private List<B> b;
Class B:
#ManyToOne
#JoinColumn(name = "aId", referencedColumnName = "id")
private A a;
private String test;
Service:
A a = new A();
//Create without children
aFacade.create(a);
//items
List<B> list = new ArrayList<>();
B b = new B();
b.setTest("Hello");
b.setA(a);
list.add(b);
//merge
a.setB(list);
aFacade.edit(a);
you hit the exception below simply because the entity isn't in the Entity Manager's session at the moment you are trying to persist it. That's due to laziness of your association.
"detached entity passed to persist: praktyki.core.entities.KoordynatorzyPraktykEntity;"
Try calling em.merge() to attach it to the session.
In the custom AuthenticationProvider from my spring project, I am trying read the list of authorities of the logged user, but I am facing the following error:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.horariolivre.entity.Usuario.autorizacoes, could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:566)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:186)
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:545)
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:124)
at org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:266)
at com.horariolivre.security.CustomAuthenticationProvider.authenticate(CustomAuthenticationProvider.java:45)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:156)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:177)
at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:94)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:211)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:57)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:343)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:260)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
Reading other topics from here in StackOverflow, I understand this happens due the way this type of atribute is handled by the framework, but i can't figure out any solution for my case. Someone can point what i am doing wrong and what I can do to fix it?
The code of my Custom AuthenticationProvider is:
#Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
#Autowired
private UsuarioHome usuario;
public CustomAuthenticationProvider() {
super();
}
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
System.out.println("CustomAuthenticationProvider.authenticate");
String username = authentication.getName();
String password = authentication.getCredentials().toString();
Usuario user = usuario.findByUsername(username);
if (user != null) {
if(user.getSenha().equals(password)) {
List<AutorizacoesUsuario> list = user.getAutorizacoes();
List <String> rolesAsList = new ArrayList<String>();
for(AutorizacoesUsuario role : list){
rolesAsList.add(role.getAutorizacoes().getNome());
}
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
for (String role_name : rolesAsList) {
authorities.add(new SimpleGrantedAuthority(role_name));
}
Authentication auth = new UsernamePasswordAuthenticationToken(username, password, authorities);
return auth;
}
else {
return null;
}
} else {
return null;
}
}
#Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
My Entity classes are:
UsuarioHome.java
#Entity
#Table(name = "usuario")
public class Usuario implements java.io.Serializable {
private int id;
private String login;
private String senha;
private String primeiroNome;
private String ultimoNome;
private List<TipoUsuario> tipoUsuarios = new ArrayList<TipoUsuario>();
private List<AutorizacoesUsuario> autorizacoes = new ArrayList<AutorizacoesUsuario>();
private List<DadosUsuario> dadosUsuarios = new ArrayList<DadosUsuario>();
private ConfigHorarioLivre config;
public Usuario() {
}
public Usuario(String login, String senha) {
this.login = login;
this.senha = senha;
}
public Usuario(String login, String senha, String primeiroNome, String ultimoNome, List<TipoUsuario> tipoUsuarios, List<AutorizacoesUsuario> autorizacoesUsuarios, List<DadosUsuario> dadosUsuarios, ConfigHorarioLivre config) {
this.login = login;
this.senha = senha;
this.primeiroNome = primeiroNome;
this.ultimoNome = ultimoNome;
this.tipoUsuarios = tipoUsuarios;
this.autorizacoes = autorizacoesUsuarios;
this.dadosUsuarios = dadosUsuarios;
this.config = config;
}
public Usuario(String login, String senha, String primeiroNome, String ultimoNome, String tipoUsuario, String[] campos) {
this.login = login;
this.senha = senha;
this.primeiroNome = primeiroNome;
this.ultimoNome = ultimoNome;
this.tipoUsuarios.add(new TipoUsuario(this, new Tipo(tipoUsuario)));
for(int i=0; i<campos.length; i++)
this.dadosUsuarios.add(new DadosUsuario(this, null, campos[i]));
}
#Id
#Column(name = "id", unique = true, nullable = false)
#GeneratedValue(strategy=GenerationType.AUTO)
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
#Column(name = "login", nullable = false, length = 16)
public String getLogin() {
return this.login;
}
public void setLogin(String login) {
this.login = login;
}
#Column(name = "senha", nullable = false)
public String getSenha() {
return this.senha;
}
public void setSenha(String senha) {
this.senha = senha;
}
#Column(name = "primeiro_nome", length = 32)
public String getPrimeiroNome() {
return this.primeiroNome;
}
public void setPrimeiroNome(String primeiroNome) {
this.primeiroNome = primeiroNome;
}
#Column(name = "ultimo_nome", length = 32)
public String getUltimoNome() {
return this.ultimoNome;
}
public void setUltimoNome(String ultimoNome) {
this.ultimoNome = ultimoNome;
}
#ManyToMany(cascade=CascadeType.ALL)
#JoinTable(name = "tipo_usuario", joinColumns = { #JoinColumn(name = "fk_usuario") }, inverseJoinColumns = { #JoinColumn(name = "fk_tipo") })
#LazyCollection(LazyCollectionOption.TRUE)
public List<TipoUsuario> getTipoUsuarios() {
return this.tipoUsuarios;
}
public void setTipoUsuarios(List<TipoUsuario> tipoUsuarios) {
this.tipoUsuarios = tipoUsuarios;
}
#ManyToMany(cascade=CascadeType.ALL)
#JoinTable(name = "autorizacoes_usuario", joinColumns = { #JoinColumn(name = "fk_usuario") }, inverseJoinColumns = { #JoinColumn(name = "fk_autorizacoes") })
#LazyCollection(LazyCollectionOption.TRUE)
public List<AutorizacoesUsuario> getAutorizacoes() {
return this.autorizacoes;
}
public void setAutorizacoes(List<AutorizacoesUsuario> autorizacoes) {
this.autorizacoes = autorizacoes;
}
#ManyToMany(cascade=CascadeType.ALL)
#JoinTable(name = "dados_usuario", joinColumns = { #JoinColumn(name = "fk_usuario") }, inverseJoinColumns = { #JoinColumn(name = "fk_dados") })
#LazyCollection(LazyCollectionOption.TRUE)
public List<DadosUsuario> getDadosUsuarios() {
return this.dadosUsuarios;
}
public void setDadosUsuarios(List<DadosUsuario> dadosUsuarios) {
this.dadosUsuarios = dadosUsuarios;
}
#OneToOne
#JoinColumn(name="fk_config")
public ConfigHorarioLivre getConfig() {
return config;
}
public void setConfig(ConfigHorarioLivre config) {
this.config = config;
}
}
AutorizacoesUsuario.java
#Entity
#Table(name = "autorizacoes_usuario", uniqueConstraints = #UniqueConstraint(columnNames = "id"))
public class AutorizacoesUsuario implements java.io.Serializable {
private int id;
private Usuario usuario;
private Autorizacoes autorizacoes;
public AutorizacoesUsuario() {
}
public AutorizacoesUsuario(Usuario usuario, Autorizacoes autorizacoes) {
this.usuario = usuario;
this.autorizacoes = autorizacoes;
}
#Id
#Column(name = "id", unique = true, nullable = false)
#GeneratedValue(strategy=GenerationType.AUTO)
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
#OneToOne
#JoinColumn(name = "fk_usuario", nullable = false, insertable = false, updatable = false)
public Usuario getUsuario() {
return this.usuario;
}
public void setUsuario(Usuario usuario) {
this.usuario = usuario;
}
#OneToOne
#JoinColumn(name = "fk_autorizacoes", nullable = false, insertable = false, updatable = false)
public Autorizacoes getAutorizacoes() {
return this.autorizacoes;
}
public void setAutorizacoes(Autorizacoes autorizacoes) {
this.autorizacoes = autorizacoes;
}
}
Autorizacoes.java
#Entity
#Table(name = "autorizacoes")
public class Autorizacoes implements java.io.Serializable {
private int id;
private String nome;
private String descricao;
public Autorizacoes() {
}
public Autorizacoes(String nome) {
this.nome = nome;
}
public Autorizacoes(String nome, String descricao) {
this.nome = nome;
this.descricao = descricao;
}
#Id
#Column(name = "id", unique = true, nullable = false)
#GeneratedValue(strategy=GenerationType.AUTO)
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
#Column(name = "nome", nullable = false, length = 16)
public String getNome() {
return this.nome;
}
public void setNome(String nome) {
this.nome = nome;
}
#Column(name = "descricao", length = 140)
public String getDescricao() {
return this.descricao;
}
public void setDescricao(String descricao) {
this.descricao = descricao;
}
}
Full project available on github
--> https://github.com/klebermo/webapp_horario_livre
You need to either add fetch=FetchType.EAGER inside your ManyToMany annotations to automatically pull back child entities:
#ManyToMany(fetch = FetchType.EAGER)
A better option would be to implement a spring transactionManager by adding the following to your spring configuration file:
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven />
You can then add an #Transactional annotation to your authenticate method like so:
#Transactional
public Authentication authenticate(Authentication authentication)
This will then start a db transaction for the duration of the authenticate method allowing any lazy collection to be retrieved from the db as and when you try to use them.
The best way to handle the LazyInitializationException is to use the JOIN FETCH directive for all the entities that you need to fetch along.
Anyway, DO NOT use the following Anti-Patterns as suggested by some of the answers:
Open Session in View
hibernate.enable_lazy_load_no_trans
Sometimes, a DTO projection is a better choice than fetching entities, and this way, you won't get any LazyInitializationException.
Adding following property to your persistence.xml may solve your problem temporarily
<property name="hibernate.enable_lazy_load_no_trans" value="true" />
As #vlad-mihalcea said it's an antipattern and does not solve lazy initialization issue completely, initialize your associations before closing transaction and use DTOs instead.
I too had this problem when I was doing unit Testing. A very Simple Solution to this problem is to use #Transactional annotation which keeps the session open till the end of the execution.
Your Custom AuthenticationProvider class should be annotated with the following:
#Transactional
This will make sure the presence of the hibernate session there as well.
The reason is that when you use lazy load, the session is closed.
There are two solutions.
Don't use lazy load.
Set lazy=false in XML or Set #OneToMany(fetch = FetchType.EAGER) In annotation.
Use lazy load.
Set lazy=true in XML or Set #OneToMany(fetch = FetchType.LAZY) In annotation.
and add OpenSessionInViewFilter filter in your web.xml
Detail See my post.
https://stackoverflow.com/a/27286187/1808417
For those who have this problem with collection of enums here is how to solve it:
#Enumerated(EnumType.STRING)
#Column(name = "OPTION")
#CollectionTable(name = "MY_ENTITY_MY_OPTION")
#ElementCollection(targetClass = MyOptionEnum.class, fetch = EAGER)
Collection<MyOptionEnum> options;
You can use hibernate lazy initializer.
Below is the code you can refer.
Here PPIDO is the data object which I want to retrieve
Hibernate.initialize(ppiDO);
if (ppiDO instanceof HibernateProxy) {
ppiDO = (PolicyProductInsuredDO) ((HibernateProxy) ppiDO).getHibernateLazyInitializer()
.getImplementation();
ppiDO.setParentGuidObj(policyDO.getBasePlan());
saveppiDO.add(ppiDO);
proxyFl = true;
}
A common practice is to put a #Transactional above your service class.
#Service
#Transactional
public class MyServiceImpl implements MyService{
...
}
First of all I'd like to say that all users who said about lazy and transactions were right. But in my case there was a slight difference in that I used result of #Transactional method in a test and that was outside real transaction so I got this lazy exception.
My service method:
#Transactional
User get(String uid) {};
My test code:
User user = userService.get("123");
user.getActors(); //org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role
My solution to this was wrapping that code in another transaction like this:
List<Actor> actors = new ArrayList<>();
transactionTemplate.execute((status)
-> actors.addAll(userService.get("123").getActors()));
There are cases where you don't need to put #Transactional annotation to your service method, like integration testing where you can just add #Transactional to your test method. You can get org.hibernate.LazyInitializationException when testing a method that just selects from database, which does not need to be transactional. For example, when you try to load an entity class which has a lazy fetch relation like below may cause this :
#OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
private List<Item> items;
so you add the #Transactional annotation to only to the test method.
#Test
#Transactional
public void verifySomethingTestSomething() {
I believe rather than enabling eager fetch, it make sense to re-initialise your entity where its needed to avoid LazyInitializationException exception
Hibernate.initialize(your entity);
For those using JaVers, given an audited entity class, you may want to ignore the properties causing the LazyInitializationException exception (e.g. by using the #DiffIgnore annotation).
This tells the framework to ignore those properties when calculating the object differences, so it won't try to read from the DB the related objects outside the transaction scope (thus causing the exception).
After changing the FetchType to EAGER, I still had the same problem. Turned out that I was using a user instance from session and the object was serialized in DB (I use Spring session JDBC), so no matter if I restarted spring boot the problem persisted. I should had requested it from the repository.
Add the annotation
#JsonManagedReference
For example:
#ManyToMany(cascade=CascadeType.ALL)
#JoinTable(name = "autorizacoes_usuario", joinColumns = { #JoinColumn(name = "fk_usuario") }, inverseJoinColumns = { #JoinColumn(name = "fk_autorizacoes") })
#JsonManagedReference
public List<AutorizacoesUsuario> getAutorizacoes() {
return this.autorizacoes;
}