I am testing Neo4j with Spring Boot and I have found the following problem when I try to insert an element using Rest API I get the error that a JSON can not be serialized to an Entity. If someone can help me or explain how to change my code or how to serialize that entity I would be very grateful. My classes are... User Entity
@NodeEntity
public class User extends AbstractEntity{
@Id
@GeneratedValue
private Long id;
private String firstname, lastname;
@NotNull @NotBlank @Email
@Index(unique = true)
private String email;
@Index(unique = true)
private String phone;
@Relationship(type = "ADDRESS")
private Set<Address> addresses = new HashSet<>();
public User() {
}
//get & set & const....
}
Adrress Entity
@NodeEntity
public class Address extends AbstractEntity{
/*Update the OMG [https://neo4j.com/developer/neo4j-ogm] and remove de id.
Keep the id in AbstractEntity*/
@Id
@GeneratedValue
private Long id;
private String street, city;
@Relationship(type = "COUNTRY")
private Country country;
public Address(String street, String city, Country country) {
this.street = street;
this.city = city;
this.country = country;
}
public Address() {
}
//get & set & const...
}
Country Entity
@NodeEntity
public class Country extends AbstractEntity {
/*Update the OMG [https://neo4j.com/developer/neo4j-ogm] and remove de id.
Keep the id in AbstractEntity*/
@Id
@GeneratedValue
private Long id;
@Index(unique=true)
private String code;
private String name;
public Country(String code, String name) {
this.code = code;
this.name = name;
}
public Country() {
}
}
Abstract Entity
@EnableNeo4jAuditing
public abstract class AbstractEntity {
public abstract Long getId();
@Transient
private SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy");
private Date created = new Date();
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (getId() == null || obj == null || !getClass().equals(obj.getClass())) {
return false;
}
return getId().equals(((AbstractEntity) obj).getId());
}
@Override
public int hashCode() {
return getId() == null ? 0 : getId().hashCode();
}
}
My simple repository class for store Users
public interface UserRepository extends Neo4jRepository<User, Long> {
User findByFirstname(String name);
@Override
void delete(User deleted);
}
My Services Class
@Service
public class UserService {
private UserRepository userRepository;
@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public Iterable<User> contact() {
return userRepository.findAll();
}
public User save(User user) {
userRepository.save(user);
return user;
}
public User show(Long id) {
return userRepository.findById(id).get();
}
public User update(Long id, User user) {
User c = userRepository.findById(id).get();
if(user.getFirstname()!=null && !user.getFirstname().trim().isEmpty())
c.setFirstname(user.getFirstname().trim());
if(user.getLastname()!=null && !user.getLastname().trim().isEmpty())
c.setLastname(user.getLastname().trim());
if(user.getEmail()!=null && !user.getEmail().trim().isEmpty())
c.setEmail(user.getEmail().trim());
userRepository.save(c);
return user;
}
public String delete(Long id) {
User user = userRepository.findById(id).get();
userRepository.delete(user);
return "";
}
}
My Controller Class
@RestController
public class UserController {
@Autowired
UserService userService;
@RequestMapping(method = RequestMethod.GET, value = "/users")
public Iterable<User> user() {
return userService.contact();
}
@RequestMapping(method = RequestMethod.POST, value = "/users")
public String save(@RequestBody User user) {
try {
userService.save(user);
}catch (org.neo4j.driver.v1.exceptions.ClientException ex){
System.err.println("******||||||||||||[{ The User exist with the same email }]||||||||||||******");
return "The User exist with the same email";
}
return user.toString();
}
@RequestMapping(method=RequestMethod.GET, value="/users/{id}")
public User show(@PathVariable Long id) {
try{
return userService.show(id);}
catch (java.util.NoSuchElementException ex){
System.err.println("******||||||||||||[{ The User do not exist }]||||||||||||******");
}
return null;
}
@RequestMapping(method=RequestMethod.PUT, value="/users/{id}")
public User update(@PathVariable Long id, @RequestBody User user) {
return userService.update(id, user);
}
@RequestMapping(method=RequestMethod.DELETE, value="/users/{id}")
public String delete(@PathVariable Long id) {
return userService.delete(id);
}
}
This is my simple scheme that I am trying to model (Neo4j is a NoSQL database is free of outline, but I try to model a simple app) enter image description here
When it tried to test the methods of the api rest, it works for me but the Country entity is not serialized to a json.
I already have data inserted into the database, which I have done using a test method declaring the objects and using the methods to save it. The problem occurs when I use the json format. When I run the curl command to test the Rest API, it does not return the country
$ curl -i -H "Accept: application/json" localhost:8088/users/1
HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Thu, 27 Sep 2018 20:38:31 GMT
{"created":"2018-09-27T19:55:21.578+0000","id":1,"firstname":"Yuniel","lastname":"Acosta Pérez","email":"[email protected]","phone":"+999999999999","addresses":[{"created":"2018-09-27T19:55:21.578+0000","id":0,"street":"Some Stree","city":"Some City","country":null}]}
As you can see, the country returns it as a null value and if it exists in the database.
When I tried to insert an element using the API it lamented an error that I can not serialize the country object to a JSON.
$ curl -i -X POST -H "Content-Type: application/json" -d '{"firstname":"Yuniel","lastname":"Acosta Pérez","email":"[email protected]","phone":"+999999999999","addresses":[{"street":"Some Stree","city":"Some City","country":[{"code":"OO","name":"ANYCOUNTRY"}]}]}' localhost:8088/users
The next mistake is the one that throws me
{"timestamp":"2018-09-27T21:07:56.365+0000","status":400,"error":"Bad Request","message":"JSON parse error: Cannot deserialize instance of com.syskayzen.hypercube.domain.Address
out of START_ARRAY token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of com.syskayzen.hypercube.domain.Address
out of START_ARRAY token\n at [Source: (PushbackInputStream); line: 1, column: 122] (through reference chain: com.syskayzen.hypercube.domain.User[\"addresses\"])","path":"/users"}
If you can tell me how to solve the problem of how to serialize the Country Entity or if it is for another reason the error.
I am using Spring Boot 2.0.5 and Spring Data Neo4j
I believe the reason Country is coming back null in your curl command is because the query is only going 1 hop deep in the database. So, it is pulling User, then going 1 hop to pull the Address node, but then it stops. To have it pull more hops along the path, you'll need to specify a depth.
You can do this by specifying a depth in the curl command and adding a parameter for 'int depth' to pass down the repository call. This will allow you to have a dynamic depth, in case you add more hops to your application that you want to retrieve.
Service method would look something like this....
Documentation for this is at the following link: https://docs.spring.io/spring-data/neo4j/docs/5.1.0.RELEASE/reference/html/#reference:session:persisting-entities:save-depth