Spring : detached entity passed to persist - java

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.

Related

Why isnĀ“t it possible to change a reference object of an entity with JPA?

I have a ticket object which should be edited. In my ticket object are attributes which reference to object(see below).
...
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "project_id", referencedColumnName="id")
private Project project;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "costCenter_id", referencedColumnName="id")
private CostCenter costCenter;
...
But when I try to update the entity I always get an error:
Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction
#PutMapping("/tickets/{id}")
#ResponseStatus(HttpStatus.OK)
public Ticket updateTicket(#RequestBody Ticket ticket) throws Exception{
Optional<Ticket> o = this.ticketRepo.findById(ticket.getId());
o.ifPresent(element -> {
if(ticket.getCostCenter() != null) {
Optional<CostCenter> c = this.costCenterRepo.findById(ticket.getCostCenter().getId());
c.ifPresent( costCenter -> {
element.setCostCenter(costCenter);
});
}
if(ticket.getProject() != null) {
Optional<Project> p = this.projectRepo.findById(ticket.getProject().getId());
p.ifPresent(project -> {
element.setProject(project);
});
}
this.ticketRepo.save(element);
});
return o.orElseThrow(() -> new NotFoundException(ticket.getId()));
}
PS: When I trigger the update without changes everything works fine.
Stacktrace: https://textsaver.flap.tv/lists/2vm5
class AuditorAwareImpl implements AuditorAware<Long> {
#Override
public Optional<Long> getCurrentAuditor() {
PersonRepository personRepo = ApplicationContextProvider.getApplicationContext().getBean(PersonRepository.class);
if(SecurityContextHolder.getContext().getAuthentication() != null) {
Person p = personRepo.findByUserPrincipalName(SecurityContextHolder.getContext().getAuthentication().getName() + "#email.com");
return Optional.of(p.getId());
} else {
Person p = personRepo.findByUserPrincipalName("SYSTEM");
return Optional.of(p.getId());
}
}
}
#Component(value = "applicationContextProvider")
class ApplicationContextProvider implements ApplicationContextAware {
private static class AplicationContextHolder {
private static final InnerContextResource CONTEXT_PROV = new InnerContextResource();
}
private static final class InnerContextResource {
private ApplicationContext context;
private void setContext(ApplicationContext context) {
this.context = context;
}
}
public static ApplicationContext getApplicationContext() {
return AplicationContextHolder.CONTEXT_PROV.context;
}
#Override
public void setApplicationContext(ApplicationContext ac) {
AplicationContextHolder.CONTEXT_PROV.setContext(ac);
}
}
#Data
#Getter
#Setter
#MappedSuperclass
#EntityListeners(AuditingEntityListener.class)
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class BaseEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", updatable = false, nullable = false)
protected Long id;
#CreatedDate
private Date createdAt;
#CreatedBy
private Long createdBy;
#LastModifiedDate
private Date updatedAt;
#LastModifiedBy
private Long updatedBy;
#PrePersist
protected void prePersist() {
if (this.createdAt == null) createdAt = new Date();
if (this.updatedAt == null) updatedAt = new Date();
}
#PreUpdate
protected void preUpdate() {
this.updatedAt = new Date();
}
#PreRemove
protected void preRemove() {
this.updatedAt = new Date();
}
}
You have a StackOverflowError which strongly suggest you've got some infinite recursion somewhere (or at least a very deep one):
Caused by: java.lang.RuntimeException: java.lang.StackOverflowError
The fact that com.mycompany.test.config.AuditorAwareImpl.getCurrentAuditor shows up repeatedly in your very long stack trace suggests that it is somehow involved in your infinite recursion and I'd wager that it comes from this class somehow triggering whatever triggered it in the first place possibly org.springframework.data.auditing.AuditingHandler. So check your AuditorAwareImpl code and/or the auditing configuration.

Cannot deserialize from String value Spring-Boot Restful project

I'm working on a Spring Boot + Maven + Restful + Hibernate project! After creating the RestController for adding new Devices in database i'm getting this error:
2018-03-28 10:15:18.786 WARN 9286 --- [nio-9090-exec-9] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `com.hhm.hsy.hibernate.models.Protocol` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{"id":5,"protocolName":"ProtocolForTesting","port":5202}'); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.hhm.hsy.hibernate.models.Protocol` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{"id":5,"protocolName":"ProtocolForTesting","port":5202}')
at [Source: (PushbackInputStream); line: 1, column: 52] (through reference chain: com.hhm.hsy.hibernate.models.Device["protocol"])
Here is my first entity:
#Entity
#Table(name = "devices", catalog = "hqm")
public class Device implements Serializable {
private static final long serialVersionUID = -8311225474375837513L;
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "device_id", unique = true, nullable = false)
private Integer id;
#Column(name = "device_name", unique = true, nullable = false)
private String deviceName;
#ManyToOne
#JoinColumn(name = "protocol_id")
private Protocol protocol;
public Device() {
}
public Device(Integer id, String deviceName, Protocol protocol) {
this.id = id;
this.deviceName = deviceName;
this.protocol = protocol;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getDeviceName() {
return deviceName;
}
public void setDeviceName(String deviceName) {
this.deviceName = deviceName;
}
public Protocol getProtocol() {
return protocol;
}
public void setProtocol(Protocol protocol) {
this.protocol = protocol;
}
And the second entity:
#Entity
#Table(name = "protocols", catalog = "hqm")
public class Protocol implements Serializable {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "protocol_id", unique = true, nullable = false)
private Integer id;
#Column(name = "protocol_name", unique = true, nullable = false, length = 45)
private String protocolName;
#Column(name = "port", nullable = false)
private Integer port;
#OneToMany(mappedBy = "protocol", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<Device> devices = new HashSet<>();
public Protocol() {
}
public Protocol(Integer id, String protocolName, Integer port) {
this.id = id;
this.protocolName = protocolName;
this.port = port;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getProtocolName() {
return protocolName;
}
public void setProtocolName(String protocolName) {
this.protocolName = protocolName;
}
public Integer getPort() {
return port;
}
public void setPort(Integer port) {
this.port = port;
}
#JsonIgnore
public Set<Device> getDevices() {
return devices;
}
#JsonIgnore
public void setDevices(Set<Device> devices) {
this.devices = devices;
}
}
Controller:
#RestController
#RequestMapping(value = "/api/devices")
#ComponentScan({"com.hhm.hsy.pmcs.*"})
public class DevicesController {
#Autowired
#Qualifier(value = "deviceService")
GenericServiceIntf deviceService;
// get ALL DEVICE
#RequestMapping(value = "", method = RequestMethod.GET)
public Map<String, Object> getDevices() {
Map<String, Object> devicesMap = new HashMap<>();
devicesMap.put("devices", deviceService.getAll());
return devicesMap;
}
//save a new DEVICE
#RequestMapping(value = "", method = RequestMethod.POST, consumes = {"application/json"}, produces = {"application/json"})
#ResponseStatus(HttpStatus.CREATED)
public ResponseEntity<Device> addDevice(#RequestBody Device device) {
deviceService.save(device);
return ResponseEntity.accepted().body(device);
}
}
Service:
#Service("deviceService")
public class DeviceServiceImpl extends GenericServiceAbstractImpl<Device, Integer> implements Serializable{
private static final long serialVersionUID = 697655212967127150L;
#Autowired
public DeviceServiceImpl(#Qualifier("deviceDao") GenericDaoIntf genericDao) {
super(genericDao);
}
}
So when i'm trying to add a new device, i get the error i mentioned upper.I don't know what is causing this exception. When I try to add with post a new Protocol it's working, table is being created in the database correctly and I am getting the data correctly in GET request as well..Please help me, I'm new to springboot and restful... if some more information is required, please just inform me and i will post it! Thank you!
I tried to reproduce your problem: here, but everything works as expected.
I think it can be related with this bug.
You should try to reproduce bug with different jackson version.
EDIT:
One more thing: It looks like you try to construct Protocol instead of Device. Show us your deviceService, if you can.
Failed to read HTTP message:
org.springframework.http.converter.HttpMessageNotReadableException:
JSON parse error: Cannot construct instance of
`com.hhm.hsy.hibernate.models.Protocol

Null columns are created on either tables when accessing data using Spring Data JPA

I am new to Spring Data JPA and Hibernate. By looking at different examples I built a working model for CRUD operations on one entity, I am having trouble in joining two tables to extract AF_NAME using AF_ID from another table which is Foreign key. A null column is created with the names of and while accessing, null is returned.please check if I am following preocedure for joins and point me to any tutorial know.
I followed this solution and still there is no progress.
#Entity
#Configuration
#EnableAutoConfiguration
#Table(name = "AFF_CONFIG")
public class AFF_CONFIG implements Serializable {
#Id
#Column(name = "AFF_CONFIG_ID")
private String AFF_CONFIG_ID;
#Column(name = "AFF_ID")
private String AFF_ID;
#Column(name = "CH_ID")
private String CH_ID;
#Column(name = "M_ID")
private Long M_ID;
#Column(name = "KEY")
private String KEY;
#Column(name = "VALUE")
private String VALUE;
#Column(name = "SYSTEM")
private String SYSTEM;
private AFF aff;
#LazyCollection(LazyCollectionOption.TRUE)
#ManyToOne
#JoinColumn(name = "AFF_ID")
public AFF getAff() {
return aff;
}
public void setAffiliate(AFF aff) {
this.aff = aff;
}
public String getAFF_CONFIG_ID() {
return AFF_CONFIG_ID;
}
public void setAFF_CONFIG_ID(String aFF_CONFIG_ID) {
AFF_CONFIG_ID = aFF_CONFIG_ID;
}
public String getAFF_ID() {
return AFF_ID;
}
public void setAFF_ID(String aFF_ID) {
AFF_ID = AFF_ID;
}
public String getCH_ID() {
return CH_ID;
}
public void setCHANNEL_ID(String cH_ID) {
CH_ID = cH_ID;
}
public Long getM_ID() {
return M_ID;
}
public void setM_ID(Long m_ID) {
M_ID = m_ID;
}
public String getKEY() {
return KEY;
}
public void setKEY(String kEY) {
KEY = kEY;
}
public String getVALUE() {
return VALUE;
}
public void setVALUE(String vALUE) {
VALUE = vALUE;
}
public String getSYSTEM() {
return SYSTEM;
}
public void setSYSTEM(String sYSTEM) {
SYSTEM = sYSTEM;
}
Second entity is:
#Entity
#Table(name = "AFF")
public class AFF implements Serializable {
#Column(name = "AFF_NAME")
private String AFF_NAME;
#Column(name = "AFF_CODE")
private String AFF_CODE;
#Id
#Column(name = "AFF_ID")
private String AFF_ID;
private Set<AFF_CONFIG> someAff = new HashSet<AFF_CONFIG>();
#LazyCollection(LazyCollectionOption.TRUE)
#OneToMany(cascade = CascadeType.ALL, mappedBy = "aff")
public Set<AFF_CONFIG> getSomeAff() {
return someAff;
}
public void setSomeAff(Set<AFF_CONFIG> someAff) {
this.someAff = someAff;
}
public String getAFF_ID() {
return AFF_ID;
}
public void setAFF_ID(String aFF_ID) {
AFF_ID = aFF_ID;
}
public String getAFF_NAME() {
return AFF_NAME;
}
public void setAFF_NAME(String aFF_NAME) {
AFF_NAME = aFF_NAME;
}
public String getAFF_CODE() {
return AFF_CODE;
}
public void setAFF_CODE(String aFF_CODE) {
AFF_CODE = aFF_CODE;
}
Since this is many to one relation I created set type in one and object type in another as defined in other places.Created a repository by extending crud and added a query. Excise the bunch of different annotations, I included them in hoping to solve the null entry.
#Repository
public interface MarketRepository extends CrudRepository<AFF_CONFIG,String> {
Page<AFF_CONFIG> findAll(Pageable pageable);
#Query("Select a,b from AFF_CONFIG a, AFF b where a.AFF_ID = b.AFF_ID" )
public List<AFF_CONFIG> getAffData();
}
the applicatoin is working fine even after some tinkering until I Included these annotations. Now there is this error:
Caused by: org.hibernate.MappingException: Could not determine type for: java.util.Set, at table: aff.
I solved the issue with the help of my Supervisor. Looks like we have to follow naming specifications for Class and variables. And one more correction is to remove collection type object and change it to just object (removed set in aff class).I will post the corrected later, to compare and contrast.

ManyToMany : MappingException: Could not determine type for: java.util.List

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;

Mapping hibernate entity with Jackson annotation

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.

Categories

Resources