Use criteria to query embeddable object - jpa

I'm using Toplink Grid(Eclipselink) as the my JPA implementation framework.
I met a a exception as below while I tried to use Criteria to query a Embeddable object:
Exception [EclipseLink-6119] (Eclipse Persistence Services - 2.1.2.v20101206-r8635): org.eclipse.persistence.exceptions.QueryException
Exception Description: The join expression
Query Key conInfo
Base domain.de1003.Employee is not valid, or for a mapping type that does not support joining.
Query: ReportQuery(referenceClass=Employee )
at org.eclipse.persistence.exceptions.QueryException.mappingForExpressionDoesNotSupportJoining(QueryException.java:659)
at org.eclipse.persistence.internal.queries.JoinedAttributeManager.prepareJoinExpression(JoinedAttributeManager.java:851)
at org.eclipse.persistence.internal.queries.JoinedAttributeManager.prepareJoinExpressions(JoinedAttributeManager.java:778)
at org.eclipse.persistence.internal.queries.ReportItem.initialize(ReportItem.java:171)
at org.eclipse.persistence.queries.ReportQuery.prepare(ReportQuery.java:1035)
at org.eclipse.persistence.queries.DatabaseQuery.checkPrepare(DatabaseQuery.java:509)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.checkPrepare(ObjectLevelReadQuery.java:822)
at org.eclipse.persistence.queries.DatabaseQuery.checkPrepare(DatabaseQuery.java:470)
at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:710)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1038)
at org.eclipse.persistence.queries.ReadAllQuery.execute(ReadAllQuery.java:381)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeInUnitOfWork(ObjectLevelReadQuery.java:1124)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2917)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1291)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1273)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1247)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.executeReadQuery(EJBQueryImpl.java:479)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.getResultList(EJBQueryImpl.java:714)
And the code I tried are as below:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<ContactInfo> cq = cb.createQuery(ContactInfo.class);
Root<Employee> root = cq.from(Employee.class);
cq.select(root.<ContactInfo> get("conInfo"));
cq.where(cb.le(root.<Long> get("employId"), 3));
TypedQuery<ContactInfo> q = em.createQuery(cq);
List<ContactInfo> results = q.getResultList();
In Which ContactInfo is an embeddable class consisting of an address and set of phones. Phone is String filed.
Any help will be very appreciated.
I check the question related to this issue:
JPA - Criteria API and EmbeddedId
But it didn't solve my question.
And I can't find any example code.
TO James:
The entity code as below:
package domain.de1003;
import java.io.IOException;
import java.io.Serializable;
import java.util.List;
import javax.persistence.AttributeOverrides;
import javax.persistence.AttributeOverride;
import javax.persistence.CascadeType;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Version;
import oracle.eclipselink.coherence.integrated.config.GridCacheCustomizer;
import org.eclipse.persistence.annotations.Customizer;
import com.tangosol.io.pof.PofReader;
import com.tangosol.io.pof.PofWriter;
import com.tangosol.io.pof.PortableObject;
#Entity(name="Employee")
#Table(name="EMPLOYEE")
#Customizer(oracle.eclipselink.coherence.integrated.config.GridCacheCustomizer.class)
public class Employee implements PortableObject,Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "EM_ID")
private long employId;
#Column(name = "FIRSTNAME")
private String firstName;
#Column(name = "LASTNAME")
private String lastName;
#Embedded
#AttributeOverrides({
#AttributeOverride(name="homePhone", column=#Column(name="HOMEPHONE")),
#AttributeOverride(name="workPhone", column=#Column(name="WORKPHONE"))
})
private ContactInfo conInfo;
#Version
private long version;
public long getEmployId() {
return employId;
}
public void setEmployId(long employId) {
this.employId = employId;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public ContactInfo getConInfo() {
return conInfo;
}
public void setConInfo(ContactInfo conInfo) {
this.conInfo = conInfo;
}
public long getVersion() {
return version;
}
public void setVersion(long version) {
this.version = version;
}
#Override
public void readExternal(PofReader pofReader) throws IOException {
employId = pofReader.readLong(1);
firstName = pofReader.readString(2);
lastName = pofReader.readString(3);
version = pofReader.readLong(4);
}
#Override
public void writeExternal(PofWriter pofWriter) throws IOException {
pofWriter.writeLong(1, employId);
if(firstName != null) pofWriter.writeString(2, firstName);
if(lastName != null) pofWriter.writeString(3,lastName);
pofWriter.writeLong(4, version);
}
#Override
public String toString() {
return "["
+ "employId = " + employId
+ " firstName = " + firstName
+ " lastName = " + lastName
+ " contact inforamtion: " + conInfo
+ "]";
}
}
and Entity ContactInfo
package domain.de1003;
import java.io.IOException;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import oracle.eclipselink.coherence.integrated.config.GridCacheCustomizer;
import org.eclipse.persistence.annotations.Customizer;
import com.tangosol.io.pof.PofReader;
import com.tangosol.io.pof.PofWriter;
import com.tangosol.io.pof.PortableObject;
#Embeddable
#Customizer(oracle.eclipselink.coherence.integrated.config.GridCacheCustomizer.class)
public class ContactInfo implements PortableObject,Serializable{
private static final long serialVersionUID = 1L;
#Column(name = "ADDRESS")
private String address;
#Column(name = "HOMEPHONE")
private String homePhone;
#Column(name = "WORKPHONE")
private String workPhone;
#Column(name = "CELLPHONE")
private String cellPhone;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getHomePhone() {
return homePhone;
}
public void setHomePhone(String homePhone) {
this.homePhone = homePhone;
}
public String getWorkPhone() {
return workPhone;
}
public void setWorkPhone(String workPhone) {
this.workPhone = workPhone;
}
public String getCellPhone() {
return cellPhone;
}
public void setCellPhone(String cellPhone) {
this.cellPhone = cellPhone;
}
#Override
public void readExternal(PofReader pofReader) throws IOException {
address = pofReader.readString(1);
homePhone = pofReader.readString(2);
workPhone = pofReader.readString(3);
cellPhone = pofReader.readString(4);
}
#Override
public void writeExternal(PofWriter pofWriter) throws IOException {
if(address != null) pofWriter.writeString(1, address);
if(homePhone != null) pofWriter.writeString(2, homePhone);
if(workPhone != null) pofWriter.writeString(3, workPhone);
if(cellPhone != null) pofWriter.writeString(4, cellPhone);
}
#Override
public String toString() {
return "["
+ "address = " + address
+ " homePhone = " + homePhone
+ " workPhone = " + workPhone
+ " cellPhone = " + cellPhone
+ "]";
}
}
For the equivalent JQPL
Query query = em.createQuery("SELECT e.conInfo FROM Employee e where e.employId < 3");
worked.

I tried reproducing this in the latest EclipseLink (a 2.5 nightly) but couldn't. I suspect it might be fixed with criteria API changes to add On support - can you give it a shot to confirm it? You might have to turn off the cache to use the latest version of EclipseLink to test with though.

Check if conInfo is the correct name of your attribute (include your entity code).
Does the equivalent JPQL work?

Related

JPA won't save an entity correctly unless the references to other entities are set

If I save this entity using JPA repository with a new defaultAssetId, it will only update the defaultAsssetId to the new value if I set defaultAsset as well. I want to be able to save without setting defaultAsset.
Same problem applies to taskType and assetRole.
package au.com.polonious.conf.entity;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;
#Entity
public class TaskTypeAssetRole implements Serializable {
#GenericGenerator(name="tasktypeassetroleidseq",
strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
parameters = {
#Parameter(name = "sequence_name", value = "tasktypeassetroleidseq"),
#Parameter(name = "initial_value", value = "1"),
#Parameter(name = "increment_size", value = "1")
})
#Id
#GeneratedValue(generator = "tasktypeassetroleidseq")
private Long id;
#Column(insertable = false, updatable=false)
private Long taskTypeId;
#Fetch(FetchMode.JOIN)
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="tasktypeid")
private TaskType taskType;
#Column(insertable = false, updatable=false)
private Long assetRoleId;
#Fetch(FetchMode.JOIN)
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="assetRoleId")
private Role assetRole;
#Column(insertable = false, updatable=false)
private Long defaultAssetId;
#Fetch(FetchMode.JOIN)
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="defaultassetid")
private Asset defaultAsset;
private Date startDate;
private Date endDate;
private String notes;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getTaskTypeId() {
return taskTypeId;
}
public void setTaskTypeId(Long taskTypeId) {
this.taskTypeId = taskTypeId;
}
public TaskType getTaskType() {
return taskType;
}
public void setTaskType(TaskType taskType) {
this.taskType = taskType;
}
public Long getAssetRoleId() {
return assetRoleId;
}
public void setAssetRoleId(Long assetRoleId) {
this.assetRoleId = assetRoleId;
}
public Role getAssetRole() {
return assetRole;
}
public void setAssetRole(Role assetRole) {
this.assetRole = assetRole;
}
public Long getDefaultAssetId() {
return defaultAssetId;
}
public void setDefaultAssetId(Long defaultAssetId) {
this.defaultAssetId = defaultAssetId;
}
public Date getStartDate() {
return startDate;
}
public void setStartDate(Date startDate) {
this.startDate = startDate;
}
public Date getEndDate() {
return endDate;
}
public void setEndDate(Date endDate) {
this.endDate = endDate;
}
public String getNotes() {
return notes;
}
public void setNotes(String notes) {
this.notes = notes;
}
}
I tried saving a taskTypeAssetRole with a new defaultAssedId without setting defaultAsset and I expected the defaultAssedId for that entry in the database to be updated.
What ended up happening was defaultAssetId didn't change although everything else in the entry did update successfully and there were no errors.
Your mapping is inherently broken. The column defaultassetiId is mapped to two different values: the field defaultAssetId and to the id of defaultAsset.
You should remove the defaultAssetId because this construct might break on any update of your JPA provider.
You can use references instead of full entities to set the reference values without loading entities from the database. See https://docs.spring.io/spring-data/jpa/docs/current/api/org/springframework/data/jpa/repository/JpaRepository.html#getReferenceById-ID-
If you don't follow this advice you should remove updatable=false if you want to update a field.

Why does id of child entity return 0 in response message in EclipseLink?

I'm using a One-To-One association between my Member and MemberRoles tables. I wanted them to share the same id as PK and FK in the database and did it. But I've got another problem. When I insert a Member, a MemberRole record is being inserted with it and Member record has the correct id in return response but MemberRole id is incorrect. It returns 0 like this:
{
"result": "Bulk user member saving is successfull. Members' informations are:",
"memberList": [
{
"id": 2,
"firstName": "Michael",
"lastName": "Schumacher",
"email": "ilkay.gune2l#kod5.org",
"enabled": false,
"memberLanguageCode": "tr",
"roleOfMember": {
"id": 0,
"email": "ilkay.gune2l#kod5.org",
"role": "ROLE_USER"
}
}
]
}
My Member Entity Class:
package com.ilkaygunel.entities;
import java.time.LocalDateTime;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
#Entity
#JsonInclude(Include.NON_NULL)
#NamedQueries({ #NamedQuery(name = "Member.findAll", query = "select m from Member m"),
#NamedQuery(name = "Member.findByFirstName", query = "select m from Member m where m.firstName =:firstName"),
#NamedQuery(name = "Member.findPasswordOfMember", query = "select m.password from Member m where m.id =:id"),
#NamedQuery(name = "Member.findByActivationToken", query = "select m from Member m where m.activationToken =:activationToken"),
#NamedQuery(name = "Member.findByEmail", query = "select m from Member m where m.email =:email") })
#Table(name = "MEMBER")
public class Member {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "MEMBER_ID")
private long id;
#Column(nullable = false)
private String firstName;
#Column(nullable = false)
private String lastName;
#Column(nullable = false, updatable = false)
private String email;
#Column(nullable = false, updatable = false)
private boolean enabled;
#Column(nullable = false)
private String password;
#Column(nullable = false)
private String memberLanguageCode;
#Column(updatable = false)
#JsonIgnore
private String activationToken;
#Column(updatable = false)
#JsonIgnore
private LocalDateTime activationTokenExpDate;
#OneToOne(cascade = CascadeType.ALL, mappedBy = "member", optional = false)
#PrimaryKeyJoinColumn(name = "MEMBER_ID")
private MemberRoles roleOfMember;
#Override
public String toString() {
return String.format("Member [id=%d, firstName='%s', lastName='%s', email='%s']", id, firstName, lastName,
email);
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
if (null != roleOfMember) {
roleOfMember.setId(id);
}
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public MemberRoles getRoleOfMember() {
return roleOfMember;
}
public void setRoleOfMember(MemberRoles roleOfMember) {
this.roleOfMember = roleOfMember;
}
public String getActivationToken() {
return activationToken;
}
public void setActivationToken(String activationToken) {
this.activationToken = activationToken;
}
public LocalDateTime getActivationTokenExpDate() {
return activationTokenExpDate;
}
public void setActivationTokenExpDate(LocalDateTime activationTokenExpDate) {
this.activationTokenExpDate = activationTokenExpDate;
}
public String getMemberLanguageCode() {
return memberLanguageCode;
}
public void setMemberLanguageCode(String memberLanguageCode) {
this.memberLanguageCode = memberLanguageCode;
}
}
And my MemberRoles Entity class:
package com.ilkaygunel.entities;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.MapsId;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import com.fasterxml.jackson.annotation.JsonIgnore;
#Entity
#NamedQueries({
#NamedQuery(name = "MemberRoles.findByEmail", query = "select mr from MemberRoles mr where mr.email = :email") })
#Table(name = "MEMBERROLES")
public class MemberRoles {
#Id
#Column(name = "MEMBERROLES_ID")
private long id;
private String email;
private String role;
#MapsId
#OneToOne(optional = false)
#JoinColumn(name = "MEMBERROLES_ID", unique = true, nullable = false, updatable = false)
#JsonIgnore
private Member member;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public Member getMember() {
return member;
}
public void setMember(Member member) {
this.member = member;
}
}
When I inserted a Member record, I check it on the database and see that Member and MemberRoles record have the same id. But why does MemberRoles area in response message has got id as 0?
My MemberSaveService class like this:
package com.ilkaygunel.service;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.mail.MessagingException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import com.ilkaygunel.constants.ConstantFields;
import com.ilkaygunel.entities.Member;
import com.ilkaygunel.entities.MemberRoles;
import com.ilkaygunel.exception.CustomException;
import com.ilkaygunel.exception.ErrorCodes;
import com.ilkaygunel.pojo.MemberOperationPojo;
#Service
public class MemberSaveService extends BaseService {
public MemberOperationPojo addUserMember(List<Member> memberList) {
return addBulkMember(memberList, ConstantFields.ROLE_USER.getConstantField());
}
public MemberOperationPojo addAdminMember(List<Member> memberList) {
return addBulkMember(memberList, ConstantFields.ROLE_ADMIN.getConstantField());
}
public MemberOperationPojo addBulkMember(List<Member> memberList, String role) {
Logger LOGGER = loggingUtil.getLoggerForMemberSaving(this.getClass());
LOGGER.log(Level.INFO, resourceBundleMessageManager.getValueOfProperty(role + "_bulkMemberAddingMethod", "en"));
MemberOperationPojo memberOperationPojo = new MemberOperationPojo();
List<Member> savedMemberList = new ArrayList<>();
try {
memberUtil.checkEmailAddressAndLanguageOnMemberList(memberList, LOGGER);
for (Member member : memberList) {
addOneMember(member, role, LOGGER);
savedMemberList.add(member);
}
memberOperationPojo.setResult(
resourceBundleMessageManager.getValueOfProperty(role + "_bulkMemberAddingSuccessfull", "en"));
memberOperationPojo.setMemberList(memberUtil.removeFieldsFromReturningMember(savedMemberList));
LOGGER.log(Level.INFO,
resourceBundleMessageManager.getValueOfProperty(role + "_bulkMemberAddingSuccessfull", "en")
+ memberList);
} catch (CustomException customException) {
LOGGER.log(Level.SEVERE,
resourceBundleMessageManager.getValueOfProperty(role + "_bulkMemberAddingFaled", "en")
+ customException.getErrorCode() + " " + customException.getErrorMessage());
memberOperationPojo.setErrorCode(customException.getErrorCode());
memberOperationPojo.setResult(customException.getErrorMessage());
} catch (Exception e) {
LOGGER.log(Level.SEVERE,
resourceBundleMessageManager.getValueOfProperty(role + "_bulkMemberAddingFaled", "en")
+ e.getMessage());
memberOperationPojo.setErrorCode(ErrorCodes.ERROR_10.getErrorCode());
memberOperationPojo.setResult(e.getMessage());
}
return memberOperationPojo;
}
private void addOneMember(Member member, String role, Logger LOGGER) throws MessagingException {
MemberOperationPojo memberOperationPojo = new MemberOperationPojo();
LOGGER.log(Level.INFO, resourceBundleMessageManager.getValueOfProperty(role + "_memberAddingMethod",
member.getMemberLanguageCode()));
member.setPassword(getHashedPassword(member.getPassword()));
member.setEnabled(false);
addMemberRolesObject(role, member);
addActivationToken(member);
memberFacade.create(member);
// mailUtil.sendActivationMail(member.getEmail(), member.getActivationToken());
memberOperationPojo.setResult(resourceBundleMessageManager.getValueOfProperty(role + "_memberAddingSuccessfull",
member.getMemberLanguageCode()));
LOGGER.log(Level.INFO, resourceBundleMessageManager.getValueOfProperty(role + "_memberAddingSuccessfull",
member.getMemberLanguageCode()) + member);
}
private String getHashedPassword(String rawPassword) {
return new BCryptPasswordEncoder().encode(rawPassword);
}
private void addMemberRolesObject(String role, Member member) {
MemberRoles rolesOfMember = new MemberRoles();
rolesOfMember.setRole(role);
rolesOfMember.setEmail(member.getEmail());
rolesOfMember.setMember(member);
member.setRoleOfMember(rolesOfMember);
}
private void addActivationToken(Member member) {
String activationToken = UUID.randomUUID().toString();
member.setActivationToken(activationToken);
LocalDateTime activationTokenExpDate = LocalDateTime.now().plusDays(1);
// LocalDateTime activationTokenExpDate = LocalDateTime.now();//Use for expire
// date test!
member.setActivationTokenExpDate(activationTokenExpDate);
}
}
My Web Service End Point Class like this:
package com.ilkaygunel.restservice;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.ilkaygunel.entities.Member;
import com.ilkaygunel.pojo.MemberOperationPojo;
import com.ilkaygunel.service.MemberSaveService;
#RestController
#RequestMapping("/memberPostWebServiceEndPoint")
public class MemberSaveWebServiceEndPoint {
#Autowired
private MemberSaveService memberSaveService;
#RequestMapping(value = "/saveUserMember", method = RequestMethod.POST)
public ResponseEntity<MemberOperationPojo> saveUserMember(#RequestBody List<Member> memberList) {
MemberOperationPojo memberOperationPojo = memberSaveService.addUserMember(memberList);
return new ResponseEntity<MemberOperationPojo>(memberOperationPojo, HttpStatus.OK);
}
#RequestMapping(value = "/saveAdminMember", method = RequestMethod.POST)
public ResponseEntity<MemberOperationPojo> saveAdminMember(#RequestBody List<Member> memberList) {
MemberOperationPojo memberOperationPojo = memberSaveService.addAdminMember(memberList);
return new ResponseEntity<MemberOperationPojo>(memberOperationPojo, HttpStatus.OK);
}
}

Spring Boot, Spring Data & MongoDB Long Sequence not getting generated

Spring Boot Version: 1.5.7.RELEASE
Spring Data
MongoDB
My attempt is to add a simple TODO in TODO Document in MongoDB. I was able to add it if I go by String id.But I want my id to be Long. And my requirement is to generate my own sequence. I am having issues generating sequence with the following code. Appreciate if you point where I am going wrong. I was able to add if I create my own id instead of using a sequence.
package com.srisris.tapasya.springjersey;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import com.srisris.tapasya.springjersey.domain.ToDo;
import com.srisris.tapasya.springjersey.domain.ToDoSequence;
import com.srisris.tapasya.springjersey.repository.ToDoRepository;
import com.srisris.tapasya.springjersey.repository.ToDoSequenceRepository;
#SpringBootApplication(scanBasePackages = { "com.srisris.tapasya.springjersey" })
public class SpringJerseyApplication extends SpringBootServletInitializer implements CommandLineRunner {
#Autowired
private ToDoRepository todoRepository;
/**
* The repository for the sequence {#link ToDoSequence}
*/
#Autowired
private ToDoSequenceRepository sequenceRepo;
// The sequence key name for the books
private static final String ToDo_SEQ_KEY = ToDo.COLLECTION_NAME;
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(SpringJerseyApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(SpringJerseyApplication.class, args);
}
#Override
public void run(String... arg0) throws Exception {
todoRepository.deleteAll();
bootStrapToDo();
}
private void bootStrapToDo() throws Exception{
DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date date = new Date();
Long sequenceId = sequenceRepo.getNextSequenceId(ToDo_SEQ_KEY);
System.out.println(" Sequence ID is " + sequenceId);
ToDo td1 = new ToDo(sequenceId,"Work on Java", "Learn Lambdas, Modules & clojures", dateFormat.format(date));
todoRepository.save(td1);
//ToDo td2 = new ToDo(sequenceRepo.getNextSequenceId(ToDo_SEQ_KEY),"Work on Swift", "Learn Optionals", dateFormat.format(date));
//todoRepository.save(td2);
}
}
ToDo Domain
package com.srisris.tapasya.springjersey.domain;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
#Document(collection = ToDo.COLLECTION_NAME)
public class ToDo {
public static final String COLLECTION_NAME = "todos";
#Id
private Long id;
private String summary;
private String description;
private String dateCreated;
public ToDo() {
}
public ToDo(Long todoID, String summary, String description, String dateCreated) {
this.id = todoID;
this.summary = summary;
this.description = description;
this.dateCreated = dateCreated;
}
public Long getId() {
return id;
}
public void setId(Long todoID) {
this.id = todoID;
}
public String getSummary() {
return summary;
}
public String getDescription() {
return description;
}
public String getDateCreated() {
return dateCreated;
}
#Override
public String toString() {
return String.format("ToDo[id=%s, summary='%s', description='%s' , dateCreated='%s']", id, summary, description,
dateCreated);
}
}
Custom Sequence Domain
ToDoSequence
package com.srisris.tapasya.springjersey.domain;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
#Document(collection = ToDoSequence.COLLECTION_NAME)
public class ToDoSequence {
public static final String COLLECTION_NAME = "todoSequence";
#Id
private String id;
private Long sequence;
public ToDoSequence() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Long getSequence() {
return sequence;
}
public void setSequence(Long seq) {
this.sequence = seq;
}
}
ToDoRepository
package com.srisris.tapasya.springjersey.repository;
import java.util.List;
import org.springframework.data.mongodb.repository.MongoRepository;
import com.srisris.tapasya.springjersey.domain.ToDo;
public interface ToDoRepository extends MongoRepository<ToDo, Long> {
public ToDo findBySummary(String summary);
public List<ToDo> findByDateCreated(String dateCreated);
}
ToDoSequenceRepository
package com.srisris.tapasya.springjersey.repository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Repository;
import com.srisris.tapasya.springjersey.domain.ToDoSequence;
#Repository
public class ToDoSequenceRepository {
#Autowired
private MongoOperations mongoOperation;
public Long getNextSequenceId(String key) throws Exception {
Query query = new Query(Criteria.where("_id").is(key));
// increase sequence id by 1
Update update = new Update();
update.inc("sequence", 1);
// return new increased id
FindAndModifyOptions options = new FindAndModifyOptions();
options.returnNew(true);
// this is the magic happened.
ToDoSequence seqId = mongoOperation.findAndModify(query, update, options, ToDoSequence.class);
// if no id, throws SequenceException
// optional, just a way to tell user when the sequence id is failed to
// generate.
if (seqId == null) {
throw new Exception(seqId + " Unable to get sequence id for key : " + key);
}
return seqId.getSequence();
}
}

Neo4j Springboot SpringData restful example not complete without relationship entity

I am using the springio accessing-neo4j-data-rest example which has the relationship as part of the Person class and really doesn't show the advantage of Neo4j. I tried creating a Family relationship entity, but can't create a relationship using a restful service with Springboot and port 8080.
My service works and creates the relationship using http://localhost:7474/db/data/node/67/relationships
Shouldn't I be able to do this (where 66 and 67 are existing Person entities):
POST to http://localhost:8080/people/67/family
{
"to" : "http://localhost:8080/people/66",
"type" : "RELATED_TO"
}
I get the error:
{
"timestamp": 1486948326367,
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/people/67/family"
}
Person.java
package hello;
import java.util.HashSet;
import java.util.Set;
import org.neo4j.ogm.annotation.GraphId;
import org.neo4j.ogm.annotation.NodeEntity;
import org.neo4j.ogm.annotation.Relationship;
#NodeEntity
public class Person {
#GraphId public Long id;
private String firstName;
private String lastName;
#Relationship(type = Family.TYPE, direction = Relationship.UNDIRECTED)
private Set<Family> family = new HashSet<Family>();
public Long getId() {
return id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Set<Family> getFamily() {
return family;
}
public void addFamily(Family f) {
family.add(f);
}
public void addFamily(Person target, String association) {
this.family.add(new Family(this, target, association));
}
public void addFamily(Person target) {
this.family.add(new Family(this, target));
}
}
Family.java
package hello;
import org.neo4j.ogm.annotation.EndNode;
import org.neo4j.ogm.annotation.GraphId;
import org.neo4j.ogm.annotation.Property;
import org.neo4j.ogm.annotation.RelationshipEntity;
import org.neo4j.ogm.annotation.StartNode;
#RelationshipEntity(type = Family.TYPE)
public class Family {
public static final String TYPE = "RELATED_TO";
#GraphId
private Long id;
#Property
private String association;
#StartNode
private Person p1;
#EndNode
private Person p2;
public Family() {
}
public Family(Person first, Person second) {
this.p1 = first;
this.p2 = second;
}
public Family(Person first, Person second, String assoc) {
this.p1 = first;
this.p2 = second;
association = assoc;
}
public Long getId() {
return id;
}
public Person getFirst() {
return p1;
}
public Person getSecond() {
return p2;
}
public String getAssociation() {
return association;
}
public void setAssociation(String association) {
this.association = association;
}
}
PersonRepository.java
package hello;
import java.util.List;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
#RepositoryRestResource(collectionResourceRel = "people", path = "people")
public interface PersonRepository extends PagingAndSortingRepository<Person, Long> {
List<Person> findByLastName(#Param("name") String name);
List<Person> findByFirstName(#Param("name") String name);
}
FamilyRepository .java
package hello;
import org.springframework.data.neo4j.repository.GraphRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
#RepositoryRestResource(collectionResourceRel = "family", path = "family") // what should go here????
public interface FamilyRepository extends GraphRepository<Family> {
// //creates a get - need a post
// #Query("MATCH (a:Traveler),(b:Traveler) WHERE a.lastName = {from} AND b.lastName = {to} CREATE (a)-[r:RELATED_TO]->(b) RETURN r")
// void worksWith(#Param("to") String to);
}
Edited:2-19-2017 - Getting closer. I needed a controller - something like this:
#RestController
public class FamilyController {
...
#RequestMapping(value = "/people/{id}/family", method = RequestMethod.POST, consumes = APPLICATION_JSON, produces = APPLICATION_JSON)
#ResponseStatus(value = HttpStatus.ACCEPTED)
#ResponseBody
Family addFamily(#RequestBody Family f, #PathVariable(value = "id") String id) {

entity association in java

I am trying to get rid of this error:
Exception Description: [class utilisateurs.modeles.Utilisateur] uses a non-entity [class java.util.Collection] as target entity in the relationship attribute [field adresses].
at org.eclipse.persistence.exceptions.ValidationException.nonEntityTargetInRelationship(ValidationException.java:1343)
.........
org.eclipse.persistence.internal.jpa.deployment.PersistenceUnitProcessor.processORMetadata(PersistenceUnitProcessor.java:526)
at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.predeploy(EntityManagerSetupImpl.java:1320)
... 36 more
with the following entity:
utilisateurs.modeles;
import adresses.Adresse;
import java.io.Serializable;
import java.util.Collection;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
#Entity(name="Utilisateur")
public class Utilisateur implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
public void setAdresses(Collection<Adresse> adresses) {
this.adresses = adresses;
}
private String firstname;
private String lastname;
private String login;
#ManyToOne(cascade=CascadeType.PERSIST)
private Collection<Adresse> adresses;
public Collection<Adresse> getAdresses() {
return adresses;
}
public Utilisateur() {
}
public Utilisateur(final String firstname, final String lastname, final String login) {
this.firstname = firstname;
this.lastname = lastname;
this.login = login;
}
//getters and setters here
#Override
public int hashCode() {
int hash = 0;
hash += (int) id;
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Utilisateur)) {
return false;
}
Utilisateur other = (Utilisateur) object;
if (this.id != other.id) {
return false;
}
return true;
}
}
If you have any idea please.
Adresse is not an Entity, maybe you just forgot the #Entity annotation on that class?
The #ManyToOne annotation defines a relationship between entities.