Such a problem. I have a DTO in which the fields of the tables boat_cards and engines are combined. Now I want to get data from table engines excluding the cardid field. The option with the #JsonIgnore annotation is not suitable, since this field may need to be displayed when querying the engines table itself Here is my code:
DAO class:
#Repository
public interface EnginesDao extends JpaRepository<Engines, Integer> {
List<Engines> findAllByCardidCardid(Integer cardid);
#Query(value = "SELECT engid, engname, engvin, engpwr, recdate FROM gims.engines where cardid = :cardid",
nativeQuery = true)
List<Engines> findAllByCardidQuery(#Param("cardid") Integer cardid);
}
Service class:
#Service
public class EnginesServiceImpl implements EnginesService{
#Autowired
private EnginesDao enginesDao;
#Override
public List<Engines> getAllByCardidQuery(Integer id) {
return enginesDao.findAllByCardidQuery(id);
}
}
DTO class:
#JsonIgnoreProperties(ignoreUnknown = true)
public class BoatCardsDto extends BoatCards implements Serializable {
private List<Engines> engines;
public BoatCardsDto(BoatCards boatCards, List<Engines> engines) {
this.cardid = boatCards.getCardid();
this.regNum = boatCards.getRegNum();
this.tiketNum = boatCards.getTiketNum();
this.boatName = boatCards.getBoatName();
this.boatType = boatCards.getBoatType();
this.boatYear = boatCards.getBoatYear();
this.boatVin = boatCards.getBoatVin();
this.parkingPlace = boatCards.getParkingPlace();
this.saCategory = boatCards.getSaCategory();
this.boatLength = boatCards.getBoatLength();
this.boatWidth = boatCards.getBoatWidth();
this.boatHeight = boatCards.getBoatHeight();
this.bodyMaterial = boatCards.getBodyMaterial();
this.boatPayload = boatCards.getBoatPayload();
this.passengersNum = boatCards.getPassengersNum();
this.serviceLife = boatCards.getServiceLife();
this.engineNum = boatCards.getEngineNum();
this.owner = boatCards.getOwner();
this.agent = boatCards.getAgent();
this.note = boatCards.getNote();
this.engines = engines;
}
public List<Engines> getEngines() {
return engines;
}
public void setEngines(List<Engines> engines) {
this.engines = engines;
}
}
and my exception is:
2023-01-26T18:02:10.206+03:00 ERROR 19892 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]:
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
[Request processing failed: org.springframework.dao.InvalidDataAccessResourceUsageException:
Unable to find column position by name: cardid; SQL [n/a]] with root cause
My engine entity:
#Entity
#Table(name = "engines")
#Data
#NoArgsConstructor
#FieldDefaults(level = AccessLevel.PRIVATE)
public class Engines {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "engid")
Integer engid;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "cardid")
BoatCards cardid;
#Column(name = "engname")
String engname;
#Column(name = "engvin")
String engvin;
#Column(name = "engpwr")
String engpwr;
#Column(name = "recdate")
#JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS")
Timestamp recdate;
}
Related
I have 2 java classes, one of them contains the other as a list by #ElementCollection.
When I try to set that list, following error occurs:
Local Exception Stack:
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.1.3.v20110304-r9073): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLSyntaxErrorException: ORA-00942: table or view does not exist
Error Code: 942
Call: SELECT t0.VERSIONS FROM MainProcess_VERSIONS t0 WHERE (t0.MainProcess_SUBJECT_ID = ?)
bind => [#id]
Query: DirectReadQuery(name="versions" sql="SELECT t0.VERSIONS
FROM MainProcess_VERSIONS t0 WHERE (t0.MainProcess_SUBJECT_ID = ?)")
at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:333)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:683)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:526)
.
.
.
at ...Editor.MAINPROCESS._persistence_propertyChange(MAINPROCESS.java)
at ...Editor.MAINPROCESS._persistence_set_versions(MAINPROCESS.java)
at ...MAINPROCESS.setVersions(MAINPROCESS.java:79)
at ...DataModel.fillSubprocessSubject(DataModel.java:643)
at ...DataModel.load(DataModel.java:321)
If I remove the #ElementCollection then I get the following error
Error Code: 942
Call:
SELECT t1.ACT_VERSION, t1.SUBJECT_ID, t1.ACT_VERSION_REMARK,
t1.ACT_VALID_TO, t1.ACT_VERSION_ACCEPTED, t1.NORMALRETURNVALUES, t1.ACT_VALID_FROM
FROM MAINPROCESS_MAINPROCESSVERSION t0, MAINPROCESSVERSION t1
WHERE ((t0.MainProcess_SUBJECT_ID = ?) AND ((t1.SUBJECT_ID = t0.SUBJECT_ID)
AND (t1.ACT_VERSION = t0.ACT_VERSION)))
bind => [#id]
Here are my classes,
MainProcess:
#Entity
public class MainProcess implements Serializable {
#Id
#Column(name = "SUBJECT_ID", nullable = false)
private Long subjectId;
...other columns
#ElementCollection
private List<MainProcessVersion> versions = new ArrayList<MainProcessVersion>();
public MainProcess() {
}
public void setVersions(List<MainProcessVersion> versions) {
this.versions = versions;
}
public List<MainProcessVersion> getVersions() {
return versions;
}
other getters and setters...
}
MainProcessVersion:
#Entity
#IdClass(MainProcessVersionPK.class)
public class MainProcessVersion implements Serializable {
#Id
#Column(name = "SUBJECT_ID", nullable = false)
#XmlTransient
private Long subjectId;
#Id
#Column(name = "ACT_VERSION")
private Long actVersion;
...other columns
private List<String> normalReturnValues;
public MainProcessVersion() {
}
getters and setters...
}
And the function in which the error occurs:
private MainProcess fillSubprocessSubject(Long Id) {
MainProcess p = someFacade.getProcess(Id);
List<MainProcessVersion> versions = someFacade.getProcessVersions(Id);
p.setVersions(versions); //error is here
return p;
}
Thanks in advance for any help.
I managed to solve my problem. Most important was to understand the difference between #ElementCollection and #OneToMany annotation. I cannot better explain like this.
So the problem was that my MainProcessVersion.java was annotated with #Entity, thus I could not add the #ElementCollection annotation to it in the MainProcess.java.
#ElementCollection //One cannot use this annotation because MainProcessVersion is an entity.
private List<MainProcessVersion> versions = new ArrayList<MainProcessVersion>();
But I need the Entity, so I created resultRow class wich is the same as my Entity class except the annotation. After query selection, I cast my result to my new resultRow class and I can set that list in the MainProcess.java.
My resultRow class:
public class MainProcessVersionResultRow implements Serializable {
private Long subjectId;
...other code
}
My old MainProcess class
#Entity
public class MainProcess implements Serializable {
#Id
#Column(name = "SUBJECT_ID", nullable = false)
private Long subjectId;
...other columns
//without #ElementCollection and the new resultRow object type
private List<MainProcessVersionResultRow> versions = new ArrayList<MainProcessVersionResultRow>();
public MainProcess() {
}
...getters. setters
}
And then, I "cast" my entity to resultRow class:
private MainProcess fillSubprocessSubject(Long subjectId) {
MainProcess p =
someFacade.getSubprocessSubject(subjectId);
List<MainProcessVersion> versions = someFacade.getProcessVersions(subjectId);
List<MainProcessVersionResultRow> versionResultRows = new ArrayList<MainProcessVersionResultRow>();
for (MainProcessVersion vs : versions) {
MainProcessVersionResultRow versionSingleResultRow = new MainProcessVersionResultRow(vs);
versionSingleResultRow.setNormalReturnValues(processReturnValues(p.getSubjectId(), vs.getActVersion()));
versionResultRows.add(versionSingleResultRow);
}
p.setVersions(versionResultRows); //does not throw an error any more
return p;
}
So conclusion:
Do not use #ElementCollection on a class that has an #Entity annotation.
I have 2 entities, with 1-to-1 association (ProfileEntity and VCardEntity)
Entity vcard:
#Entity
#Table(name = "vcard")
#AllArgsConstructor
#NoArgsConstructor
#Data
#SequenceGenerator(name="vcard_id_seq_generator", sequenceName="vcard_id_seq", allocationSize = 1)
public class VCardEntity {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "vcard_id_seq_generator")
#Column(name="vcard_id")
Long id;
String account;
#Column(name = "first_name")
String firstName;
#Column(name = "last_name")
String lastName;
#Column(name = "pbxinfo_json")
String pbxInfoJson;
#Column(name = "avatar_id")
String avatarId;
#OneToOne(mappedBy = "vcard")
ProfileEntity profile;
}
entity Profile:
#Entity
#AllArgsConstructor
#NoArgsConstructor
#Data
#Table(name = "profile")
public class ProfileEntity {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Column(name = "profile_id")
private Long profileId;
private String account;
#Column(name = "product_id")
private String productId;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "vcard_id", referencedColumnName = "vcard_id")
private VCardEntity vcard;
}
I use map struct as follow:
public class CycleAvoidingMappingContext {
private Map<Object, Object> knownInstances = new IdentityHashMap<Object, Object>();
#BeforeMapping
public <T> T getMappedInstance(Object source, #TargetType Class<T> targetType) {
return targetType.cast(knownInstances.get(source));
}
#BeforeMapping
public void storeMappedInstance(Object source, #MappingTarget Object target) {
knownInstances.put( source, target );
}
}
#Mapper(componentModel = "spring")
public interface EntityToProfile {
ProfileEntity profileToEntity(Profile profile, #Context CycleAvoidingMappingContext context);
Profile entityToProfile(ProfileEntity entity, #Context CycleAvoidingMappingContext context);
}
#Mapper(componentModel = "spring")
public interface EntityToVCard {
VCard entityToVcard(VCardEntity entity, #Context CycleAvoidingMappingContext context);
VCardEntity vcardToEntity(VCard vcard, #Context CycleAvoidingMappingContext context);
}
Finally i call mapping in my service:
#Service
#RequiredArgsConstructor
#Slf4j
public class DefaultChatService implements ChatService {
private final ProfileRepository profileRepository;
private final EntityToProfile entityToProfileMapper;
private final EntityToVCard entityToVCardMapper;
#Override
public List<Profile> findAllProfile(Optional<Long> id) {
if (id.isPresent()) {
Optional<ProfileEntity> result = profileRepository.findById(id.get());
if (result.isPresent()) {
Profile profile = entityToProfileMapper.entityToProfile(result.get(), new CycleAvoidingMappingContext());
return Stream.of(profile).collect(Collectors.toList());
}
}
return new ArrayList<Profile>();
}
}
and i got the error
ERROR 15976 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.StackOverflowError] with root cause
java.lang.StackOverflowError: null
Any thoughts how can i fix it?
In my view i did everything as it's written here Prevent Cyclic references when converting with MapStruct but it doesn't work for me
Found a solution, all i had to do was to change from #Value to #Data for my models
example given:
#Data
public class Profile {
Long profileId;
String account;
String productId;
VCard vcard;
}
and
#Data
public class VCard {
Long id;
String account;
String firstName;
String lastName;
String pbxInfoJson;
String avatarId;
Profile profile;
}
Otherwise mapstruct could not generate proper mapping code. It was trying to store an instance in knownInstances after creating an object, for example Profile. But because #value doesn't provide a way to set properties after creating the object (immutable object) it had to create all settings first and then use all args constructor which led to a mapping profile first which in turn was trying to do the same and map vcard first before storing the VCard object in knownInstances.
This is why the cyclic reference problem could not be solved
Properly generated code:
public Profile entityToProfile(ProfileEntity entity, CycleAvoidingMappingContext context) {
Profile target = context.getMappedInstance( entity, Profile.class );
if ( target != null ) {
return target;
}
if ( entity == null ) {
return null;
}
Profile profile = new Profile();
context.storeMappedInstance( entity, profile );
profile.setAccount( entity.getAccount() );
profile.setProductId( entity.getProductId() );
profile.setDeviceListJson( entity.getDeviceListJson() );
profile.setLastSid( entity.getLastSid() );
profile.setBalanceValue( entity.getBalanceValue() );
profile.setBalanceCurrency( entity.getBalanceCurrency() );
profile.setStatusJson( entity.getStatusJson() );
profile.setData( entity.getData() );
profile.setMissedCallsCount( entity.getMissedCallsCount() );
profile.setFirstCallSid( entity.getFirstCallSid() );
profile.setLastMissedCallSid( entity.getLastMissedCallSid() );
profile.setRemoveToCallSid( entity.getRemoveToCallSid() );
profile.setOutgoingLines( entity.getOutgoingLines() );
profile.setFeatures( entity.getFeatures() );
profile.setPermissions( entity.getPermissions() );
profile.setVcard( vCardEntityToVCard( entity.getVcard(), context ) );
return profile;
}
}
As you can see, firstly, it saves the object in context.storeMappedInstance( entity, profile ); and then fills the properties.
I'm trying to integrate sorting with Pageable on joined fields with the use of #Query annotation from Spring Data.
1st interface's method (without #Query but with the Pageable) works like a charm. Same like when I'm fetching only one Employee with the #Query but instead of Pageable I'm using Optional<Employee> there (3rd method). But the fun begins when I try to put these two all together in one - it won't work anymore.
When I try to sort the data by name field it screams with this error:
Caused by: org.hibernate.QueryException: could not resolve property: name of: (....).model.employee.Employee
So the question is: how to tell spring to look for name in joined fields? How to do this with Spring Data?
I've already tried several things but they didn't work or I still don't know how to use them properly:
someone suggested to add countQuery to the #Query parameters so this corresponds somehow with the pagination (spring data jpa #query and pageable)
I've followed Baeldung's tutorial but this doesn't cover joins
Spring-Data FETCH JOIN with Paging is not working also suggested using countQuery but I'd prefer to stick to Page<Employee> rather than List<Employee>.
I'll leave some samples of the code below. Feel free to ask for update if I omitted something important.
// Employee
#Entity
#Table(name = "employee", schema = "emp")
#Data
#NoArgsConstructor
public class Employee {
private static final String SEQUENCE = "EMPLOYEE_SEQUENCE";
#Id
#SequenceGenerator(sequenceName = SEQUENCE, name = SEQUENCE, allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQUENCE)
private Long id;
#Column(name = "employee_number")
private String employeeNumber;
#Column
#Enumerated(EnumType.STRING)
private EmployeeStatus status;
#OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
#JoinColumn(name = "id_details")
private Details details;
// some other fields ...
}
// Details
#Entity
#Table(name = "details", schema = "emp")
#Data
#NoArgsConstructor
public class Details {
private static final String SEQUENCE = "DETAILS_SEQUENCE";
#Id
#SequenceGenerator(sequenceName = SEQUENCE, name = SEQUENCE, allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQUENCE)
private Long id;
private String name;
private String surname;
// some other fields ...
}
// EmployeeDTO
#NoArgsConstructor
#AllArgsConstructor
#Data
#Builder(toBuilder = true)
public class EmployeeDTO {
private Long id;
private String employeeNumber;
private String status;
private String name;
private String surname;
// some other fields ...
}
// EmployeeRepository
#Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
// 1st method
Page<Employee> findByStatus(EmployeeStatus status, Pageable pageable);
// 2nd method
#Query(value = "select e from Employee e join e.details where e.status = :status",
countQuery = "select count(*) from Employee e join e.details where e.status = :status")
Page<Employee> getEmployeeDetails(#Param("status") EmployeeStatus status, Pageable pageable);
// 3rd method
#Query("select e from Employee e join fetch e.details where e.id = :id")
Optional<Employee> findByIdWithDetails(Long id);
// ...
}
// EmployeeService
#Service
public class EmployeeService {
private final EmployeeRepository employeeRepository;
private final EntityDtoConverter entityDtoConverter;
#Autowired
public EmployeeService(EmployeeRepository employeeRepository, EntityDtoConverter entityDtoConverter) {
this.employeeRepository = employeeRepository;
this.entityDtoConverter = entityDtoConverter;
}
public EmployeeResponse getEmployeesByStatus(EmployeeStatus status, int pageSize, int pageIndex, Sort.Direction sortDirection, String sortColumn) {
Page<EmployeeDTO> employeePage = employeeRepository.findByStatus(status, PageRequest.of(pageIndex, pageSize, Sort.by(sortDirection, sortColumn)))
.map(entityDtoConverter::convertEmployeeBaseToDto);
return new EmployeeResponse(employeePage);
}
public EmployeeResponse getEmployeeDetails(EmployeeStatus status, int pageSize, int pageIndex, Sort.Direction sortDirection, String sortColumn) {
Page<EmployeeDTO> employeePage = employeeRepository.getEmployeeDetails(status, PageRequest.of(pageIndex, pageSize, Sort.by(sortDirection, sortColumn)))
.map(entityDtoConverter::convertToEmployeeWithDetailsDto);
return new EmployeeResponse(employeePage);
}
// ...
}
// EntityDtoConverter
#Component
public class EntityDtoConverter {
public EmployeeDTO convertEmployeeBaseToDto(Employee entity) {
return EmployeeDTO.builder()
.id(entity.getId())
.employeeNumber(entity.getEmployeeNumber())
.status(entity.getStatus())
.build();
}
public EmployeeDTO convertToEmployeeWithDetailsDto(Employee entity) {
return convertEmployeeBaseToDto(entity).toBuilder()
.name(entity.getDetails().getName())
.surname(entity.getDetails().getSurname())
.build();
}
// ...
}
EDIT:
This is one of the methods of my rest controller:
#GetMapping
public ResponseEntity<EmployeeResponse> getEmployeesByStatus(EmployeeStatus status, int pageSize, int pageIndex, String sortDirection, String sortColumn) {
try {
EmployeeResponse employeeResponse = employeeService.getEmployeesByStatus(status, pageSize, pageIndex, Sort.Direction.fromString(sortDirection), sortColumn);
return employeeResponse.getTotalElements().equals(0L) ? ResponseEntity.noContent().build() : ResponseEntity.ok(employeeResponse);
} catch (Exception e) {
log.error(ERROR_MESSAGE, e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
Try below code.
Specification<Employee> joins = (employee, query, cb) -> {
Join<Employee, Detail> details = employee.join("details");
return cb.and(
employee.equal(employee.get("name", name)),
details.equal(details.get("name", detailName))
);
};
PageRequest pageRequest = new PageRequest(0, 2, new Sort(Sort.Direction.DESC, "name"));
Page<Employee> customerPage = employeeRepository.findAll(joins, pageRequest);
Here we are trying to inform JPA that this name is foreign key for Employee table.
(column and variable name changed after posting question)i am writing join query using entityManager.createNativeQuery(somequery) in jpa custom method when i run code i get following error :
com.ibm.db2.jcc.am.SqlException: [jcc][10150][10300][4.12.56] Invalid >parameter: Unknown column name exc_seq_nbr. ERRORCODE=-4460, SQLSTATE=null
i am using IBM DB2 server and spring boot
exceptionTenderPK (object in entity class) is not being mapped correctly thats why getting invalid column can someone please tell me how to map exceptionTenderPK object class
Note: i cant use #OneToMany in this case because tables are unrelated
#Entity
#Table(name = "Table_name")
#Data
public class MainPojoclass {
#EmbeddedId
#JsonProperty(value = "mainPojoclassPK")
private MainPojoclassPK mainPojoclassPK;
#Column(name = "amt")
#JsonProperty(value = "amt")
private BigDecimal amt;
#Column(name = "tndid")
#JsonProperty(value = "tndid")
private String tndid;
#Column(name = "cde")
#JsonProperty(value = "cde")
private String cde;
#Column(name = "ind")
#JsonProperty(value = "ind")
private String ind;
#Column(name = "user")
#JsonProperty(value = "user")
private String user;
#Column(name = "updatedtime")
#JsonProperty(value = "updatedtime")
private Date updatedtime;
#Column(name = "src")
#JsonProperty(value = "src")
private String src;
#Column(name = "stat")
#JsonProperty(value = "stat")
private String stat;
}
#Transactional
public interface JoinQueryRepository extends JpaRepository<MainPojoclass, Long>, JoinQueryRepositoryCustom{
}
public interface JoinQueryRepositoryCustom {
List<MainPojoclass> getGRDetails(MainPojoclass et,Date reportDate);
}
public class JoinQueryRepositoryImpl implements JoinQueryRepositoryCustom {
#PersistenceContext
EntityManager entityManager;
#SuppressWarnings("all")
#Override
public List<MainPojoclass> getGRDetails(MainPojoclass et,Date rdate) {
String queryStr = "select et.Salss_DTE from table et"
+ " join dte etr on et.Salss_DTE = etr.Salss_DTE where et.nbr =? ";
List<MainPojoclass> datalist = null;
Query query = entityManager.
createNativeQuery(queryStr,"mapping")
.setParameter(1, 222);
datalist = query.getResultList();
return datalist;
}
}
The error says that there is no column exc_seq_nbr and you used that in your EntityResult mapping.
In your query you only return et.SLS_DTE you have to return all columns that are in the result set mapping.
Hi all since i am not getting any solutions i am going with below solution it works for me and removing #SqlResultSetMapping below code is working without sql result set mapping
Query q = em.createNativeQuery(queryStr);
List<Object[]> resultList = q.getResultList();
for (Object[] result : resultList) {
entityObj.setReason(result[0].toString);
//rest attribute will convert from result[1].toString to corresponding
// data type and set to entity object
}
I am working on a Spring-MVC application in which I am trying to search for List of GroupNotes in database. The mapping in my project is GroupCanvas has one-to-many mapping with GroupSection and GroupSection has one-to-many mapping with GroupNotes. Because of these mappings, I was getting LazyInitializationException. As suggested on SO, I should be converting the objects to a DTO objects for transfer. I checked on net, but couldnt find a suitable way to translate those.
I have just created a new List to avoid the error, but one field is still giving me an error. I would appreciate if anyone tells me either how to fix this error or convert the objects to a DTO objects so they can be transferred.
Controller code :
#RequestMapping(value = "/findgroupnotes/{days}/{canvasid}")
public #ResponseBody List<GroupNotes> findGroupNotesByDays(#PathVariable("days")int days, #PathVariable("canvasid")int canvasid){
List<GroupNotes> groupNotesList = this.groupNotesService.findGroupNotesByDays(days,canvasid);
List<GroupNotes> toSendList = new ArrayList<>();
for(GroupNotes groupNotes : groupNotesList){
GroupNotes toSendNotes = new GroupNotes();
toSendNotes.setMnotecolor(groupNotes.getMnotecolor());
toSendNotes.setNoteCreationTime(groupNotes.getNoteCreationTime());
toSendNotes.setMnotetag(groupNotes.getMnotetag());
toSendNotes.setMnotetext(groupNotes.getMnotetext());
toSendNotes.setAttachCount(groupNotes.getAttachCount());
toSendNotes.setNoteDate(groupNotes.getNoteDate());
toSendList.add(toSendNotes);
}
return toSendList;
}
GroupNotesDAOImpl :
#Override
public List<GroupNotes> searchNotesByDays(int days, int mcanvasid) {
Session session = this.sessionFactory.getCurrentSession();
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_YEAR, -days);
long daysAgo = cal.getTimeInMillis();
Timestamp nowMinusDaysAsTimestamp = new Timestamp(daysAgo);
GroupCanvas groupCanvas = (GroupCanvas) session.get(GroupCanvas.class,mcanvasid);
Query query = session.createQuery("from GroupSection as n where n.currentcanvas.mcanvasid=:mcanvasid");
query.setParameter("mcanvasid", mcanvasid);
List<GroupSection> sectionList = query.list();
List<GroupNotes> notesList = new ArrayList<GroupNotes>();
for (GroupSection e : sectionList) {
System.out.println("Section name is "+e.getMsectionname());
GroupSection groupSection = (GroupSection) session.get(GroupSection.class,e.getMsectionid());
Query query1 = session.createQuery("from GroupNotes as gn where gn.ownednotes.msectionid=:msectionid and gn.noteCreationTime >:limit");
query1.setParameter("limit", nowMinusDaysAsTimestamp);
query1.setParameter("msectionid",e.getMsectionid());
notesList.addAll(query1.list());
}
// I am getting the data below, but I get JSON errors.
for(GroupNotes groupNotes : notesList){
System.out.println("Group notes found are "+groupNotes.getMnotetext());
}
return notesList;
}
GroupCanvas model :
#Entity
#Table(name = "membercanvas")
public class GroupCanvas{
#OneToMany(mappedBy = "currentcanvas",fetch=FetchType.LAZY, cascade = CascadeType.REMOVE)
#JsonIgnore
private Set<GroupSection> ownedsection = new HashSet<>();
#JsonIgnore
public Set<GroupSection> getOwnedsection() {
return this.ownedsection;
}
public void setOwnedsection(Set<GroupSection> ownedsection) {
this.ownedsection = ownedsection;
}
}
GroupSection model :
#Entity
#Table(name = "membersection")
public class GroupSection{
#OneToMany(mappedBy = "ownednotes", fetch = FetchType.EAGER,cascade = CascadeType.REMOVE)
#JsonIgnore
private Set<GroupNotes> sectionsnotes = new HashSet<>();
public Set<GroupNotes> getSectionsnotes(){
return this.sectionsnotes;
}
public void setSectionsnotes(Set<GroupNotes> sectionsnotes){
this.sectionsnotes=sectionsnotes;
}
}
GroupNotes model :
#Entity
#Table(name="groupnotes")
public class GroupNotes{
#Id
#Column(name="mnoteid")
#GeneratedValue(strategy = GenerationType.SEQUENCE,generator = "mnote_gen")
#SequenceGenerator(name = "mnote_gen",sequenceName = "mnote_seq")
#org.hibernate.annotations.Index(name = "mnoticesidindex")
private int mnoticesid;
#Column(name = "mnotetext")
private String mnotetext;
#Column(name = "mnoteheadline")
private String mnotetag;
#Column(name = "mnotecolor")
private String mnotecolor;
#Column(name = "mnoteorder")
private double mnoteorder;
#Column(name = "attachmentcount")
private int attachCount;
#Column(name = "notedate")
private String noteDate;
#Column(name = "uploader")
private String uploader;
#Column(name = "activeedit")
private boolean activeEdit;
#Column(name = "notedisabled")
private boolean noteDisabled;
#Column(name = "noteinactive")
private boolean noteInActive;
#Column(name = "notecreatoremail")
private String noteCreatorEmail;
#Column(name = "prefix")
private String prefix;
#Column(name = "timestamp")
private Timestamp noteCreationTime;
#Transient
private boolean notRead;
#Transient
private String tempNote;
#Transient
private String canvasUrl;
#ManyToOne
#JoinColumn(name = "msectionid")
#JsonIgnore
private GroupSection ownednotes;
#JsonIgnore
public GroupSection getOwnednotes(){return this.ownednotes;}
public void setOwnednotes(GroupSection ownednotes){this.ownednotes=ownednotes;}
#JsonIgnore
public int getOwnedSectionId(){
return this.ownednotes.getMsectionid();
}
#OneToMany(mappedBy = "mnotedata",fetch = FetchType.LAZY,cascade = CascadeType.REMOVE)
#JsonIgnore
private Set<GroupAttachments> mattachments = new HashSet<>();
public Set<GroupAttachments> getMattachments() {
return this.mattachments;
}
public void setMattachments(Set<GroupAttachments> mattachments) {
this.mattachments = mattachments;
}
#OneToMany(mappedBy = "mhistory",fetch = FetchType.LAZY,cascade = CascadeType.REMOVE)
#JsonIgnore
private Set<GroupNoteHistory> groupNoteHistorySet = new HashSet<>();
public Set<GroupNoteHistory> getGroupNoteHistorySet(){
return this.groupNoteHistorySet;
}
public void setGroupNoteHistorySet(Set<GroupNoteHistory> groupNoteHistorySet){
this.groupNoteHistorySet = groupNoteHistorySet;
}
#OneToMany(mappedBy = "unreadNotes",fetch = FetchType.LAZY,cascade = CascadeType.REMOVE)
#JsonIgnore
private Set<UnreadNotes> unreadNotesSet = new HashSet<>();
public Set<UnreadNotes> getUnreadNotesSet(){
return this.unreadNotesSet;
}
public void setUnreadNotesSet(Set<UnreadNotes> unreadNotesSet){
this.unreadNotesSet = unreadNotesSet;
}
//getters and setters ignored
}
Error log :
org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: (was java.lang.NullPointerException) (through reference chain: java.util.ArrayList[0]->com.journaldev.spring.model.GroupNotes["ownedSectionId"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: java.util.ArrayList[0]->com.journaldev.spring.model.GroupNotes["ownedSectionId"])
Kindly let me know what to do, as I am stuck on that error since some time.
What I think that happens is Jackson tries to serialize all fields in the hierarchy based on getter methods. In some situation NullPointerException is thrown in the following method:
#JsonIgnore
public int getOwnedSectionId(){
return this.ownednotes.getMsectionid();
}
replace it with the following method:
#JsonIgnore
public int getOwnedSectionId(){
if(this.ownednotes != null)
return this.ownednotes.getMsectionid();
return 1;
}
I don't have an explanation why jackson tries to serialize it when is market with #JsonIgnore but you can give a try with my proposal
I would appreciate if anyone tells me either how to fix this error or convert the objects to a DTO objects so they can be transferred.
We use DozerMapper at work for this purpose.
Instead of doing that mapping manually you might want to take a look at Blaze-Persistence Entity Views which can be used to efficiently implement the DTO pattern with JPA. Here a quick code sample how your problem could be solved
First you define your DTO as entity view
#EntityView(GroupNotes.class)
public interface GroupNoteView {
#IdMapping("mnoticesid") int getId();
String getMnotecolor();
String getMnotetag();
String getMnotetext();
String getNoteDate();
Timestamp getNoteCreationTime();
int getAttachCount();
}
Next you adapt your DAO to make use of it
#Override
public List<GroupNoteView> searchNotesByDays(int days, int mcanvasid) {
EntityManager entityManager = // get the entity manager from somewhere
CriteriaBuilderFactory cbf = // factory for query building from Blaze-Persistence
EntityViewManager evm = // factory for applying entity views on query builders
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_YEAR, -days);
long daysAgo = cal.getTimeInMillis();
Timestamp nowMinusDaysAsTimestamp = new Timestamp(daysAgo);
CriteriaBuilder<GroupNotes> cb = cbf.create(entityManager, GroupNotes.class, "note")
.where("noteCreationTime").gt(nowMinusDaysAsTimestamp)
.where("ownednotes.ownedcanvas.mcanvasid").eq(mcanvasid);
return evm.applySetting(EntityViewSetting.create(GroupNoteView.class), cb)
.getResultList();
}
And finally the calling code
#RequestMapping(value = "/findgroupnotes/{days}/{canvasid}")
public #ResponseBody List<GroupNoteView> findGroupNotesByDays(#PathVariable("days")int days, #PathVariable("canvasid")int canvasid){
return this.groupNotesService.findGroupNotesByDays(days, canvasid);
}