Spring JPA REST One of many

I wanted to extend the Access to JPA data example with REST by adding an address list to the Person object. So, I added an @OneToMany list with @OneToMany annotation:

 @Entity public class Person { @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id; private String firstName; private String lastName; @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL) private List<Address> addresses = new ArrayList<>(); // get and set methods... } 

The Address class is very simple:

 @Entity public class Address { @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id; private String street; private String number; // get and set methods... } 

And finally, I added the AddressRepository interface:

 public interface AddressRepository extends PagingAndSortingRepository<Address, Long> {} 

Then I tried to send a message with some addresses:

 curl -i -X POST -H "Content-Type:application/json" -d '{ "firstName" : "Frodo", "lastName" : "Baggins", "addresses": [{"street": "somewhere", "number": 1},{"street": "anywhere", "number": 0}]}' http://localhost:8080/people 

The error I get is:

 Could not read document: Failed to convert from type [java.net.URI] to type [ws.model.Address] for value 'street'; nested exception is java.lang.IllegalArgumentException: Cannot resolve URI street. Is it local or remote? Only local URIs are resolvable. (through reference chain: ws.model.Person[\"addresses\"]->java.util.ArrayList[1]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Failed to convert from type [java.net.URI] to type [ws.model.Address] for value 'street'; nested exception is java.lang.IllegalArgumentException: Cannot resolve URI street. Is it local or remote? Only local URIs are resolvable. (through reference chain: ws.model.Person[\"addresses\"]->java.util.ArrayList[1]) 

What is the right method for creating one-to-many and many-to-many relationships and for post json objects?

+8
java rest spring-data-jpa spring-data-rest
source share
3 answers

You must first send two addresses, and then return their URL (for example, http: // localhost: 8080 / addresses / 1 and http: // localhost: 8080 / addresses / 2 ) in your user POST:

 curl -i -X POST -H "Content-Type:application/json" -d '{ "firstName" : "Frodo", "lastName" : "Baggins", "addresses": ["http://localhost:8080/addresses/1","http://localhost:8080/addresses/2"]}' http://localhost:8080/people 

If you want to save the person first and then add their addresses, you can do this:

 curl -i -X POST -H "Content-Type:application/json" -d '{ "firstName" : "Frodo", "lastName" : "Baggins"}' http://localhost:8080/people curl -i -X POST -H "Content-Type:application/json" -d '{"street": "somewhere", "number": 1}' http://localhost:8080/addresses curl -i -X POST -H "Content-Type:application/json" -d '{"street": "anywhere", "number": 0}' http://localhost:8080/addresses curl -i -X PATCH -H "Content-Type: text/uri-list" -d "http://localhost:8080/addresses/1 http://localhost:8080/addresses/2" http://localhost:8080/people/1/addresses 
+6
source share

Should your holiday service not take a face instead of an address?

 public interface PersonRepository extends PagingAndSortingRepository<Person, Long> {} 

Or maybe you are trying to make two different leisure services that I don’t understand. You should have only one service for recreation, in which a person accepts, in which there are address entries.

0
source share

I managed to solve this problem without exporting the reference repository. This is adding annotations on top of the interface. In your example, it will be like this:

 @RepositoryRestResource(exported = false) public interface AddressRepository extends CrudRepository<Address, Long> { } 

This partially fixes the problem since Spring Data will not distribute foreign keys for you. However, it will be stored in your Person and address (without reference to the person who belongs). Then, if we made another API call to update these missing foreign keys, you could get the person through the API with all its associated addresses - as @Francesco Pitzalis noted

I hope this helps. Just the last note. I am still working on this because I find it ridiculous (as well as basic and necessary) that Hibernate cannot distribute foreign keys for us. It should be possible somehow.


EDITED: Indeed, it was possible. In the implementation below, the entity and its children can be stored, distributing foreign keys to them for the architecture based on Spring Data (Rest - how we place repositories), Hibernate 5.0.12Final and MySQL with InnoDB storage mechanism (not in the database).

 @Entity public class Producto implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String nombre; @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) @JoinColumn(name = "producto_id") private List<Formato> listaFormatos; //Constructor, getters and setters } 

https://docs.jboss.org/hibernate/jpa/2.1/api/javax/persistence/JoinColumn.html - This was important.

 @Entity public class Formato implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private Integer cantidad; private String unidadMedida; @ManyToOne private Producto producto; //Constructor, getters and setters } @RepositoryRestResource public interface ProductoRepository extends CrudRepository<Producto, Long> { } @RepositoryRestResource public interface FormatoRepository extends CrudRepository<Formato, Long> { } spring.datasource.url=jdbc:mysql://localhost:3306/(database name) spring.datasource.username=(username) spring.datasource.password=(password) spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=create-drop spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect 

This is extremely important. You need to know where Hibernate runs SQL statements in order to properly install the dialect. For me, the storage engine for my tables is InnoDB. The following link helped. What mysql driver am i using with spring / hibernate?

 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-rest</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> 

The only thing that I could not explain was that now I can export the "child" repository, and it still works fine. Any ideas guys?

0
source share

All Articles