I am stuck on something and after a day of searching and trying different things I am throwing in the towel. I have 2 basic domains, a blog post and an author. I have left a little code out to keep this post short.
#Entity
public class Post {
#Id #GeneratedValue
private Long id;
private String title;
#Column(columnDefinition = "TEXT")
private String body;
#Column(columnDefinition = "TEXT")
private String teaser;
private String slug;
#CreatedDate
#Temporal(TemporalType.TIMESTAMP)
private Date postedOn;
#ManyToOne
private Author author;
// getters & setters
}
#Entity
public class Author {
#Id
#GeneratedValue
private Long id;
private String firstName;
private String lastName;
private String email;
// getters & setters
}
The controller looks like this
#RestController
#RequestMapping("/posts")
public class PostController {
private PostService postService;
#Autowired
public PostController(PostServiceImpl postService){
this.postService = postService;
}
#RequestMapping( value = "/", method = RequestMethod.GET )
public Iterable<Post> list(){
return postService.list();
}
#RequestMapping( value = "/", method = RequestMethod.POST )
public Post create(#RequestBody Post post){
return postService.save(post);
}
#RequestMapping( value = "/{id}", method = RequestMethod.GET )
public Post read(#PathVariable(value="id") long id){
return postService.getPost(id);
}
#RequestMapping( value = "/{id}", method = RequestMethod.PUT )
public String update(#PathVariable(value="id") int id){
return "post.update()";
}
#RequestMapping( value = "/{id}", method = RequestMethod.DELETE )
public String delete(#PathVariable(value="id") int id){
return "post.delete()";
}
}
And all the service method does is take the Post POJO and call the save method on the repository. This is my question and I feel dumb for even asking it. When I post JSON from Postman with no author (null) everything works fine. I am just not sure how the heck to post a json object with a new author or an existing one.
This works
{
"title" : "A new post created from JSON",
"slug" : "a-new-post",
"teaser" : "post teaser",
"body" : "post body",
"postedOn" : "2015-11-07"
}
When I try and post this JSON
{
"title" : "A new post created from JSON",
"slug" : "a-new-post",
"teaser" : "post teaser",
"body" : "post body",
"postedOn" : "2015-11-07",
"author" : {
"firstName": "Joe",
"lastName": "Smith",
"email": "jsmith#gmail.com"
}
}
I get the following error
{
"timestamp": 1447018768572,
"status": 500,
"error": "Internal Server Error",
"exception": "org.springframework.dao.InvalidDataAccessApiUsageException",
"message": "org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : com.therealdanvega.domain.Post.author -> com.therealdanvega.domain.Author; nested exception is java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : com.therealdanvega.domain.Post.author -> com.therealdanvega.domain.Author",
"path": "/posts/"
}
You first need to persist the Author. From the Post point of view, the Author you are presenting to it is Transient as it has no id, thus mapping cannot be done between Post and Author.
So create a persistent object of the Author and then insert it into the Post entity.
Related
I try to make an API call with the post method via postman to my spring boot application.
Here is the input:
{
"username": "name",
"password": "1234",
"age": 12,
"salary": 5000,
"role": 1
}
Here is the code in the controller:
#RequestMapping(value = "/signup", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> saveUser(#RequestBody UserDto user) {
try {
System.out.println(user.getUsername()); // => name
System.out.println(user.getPassword()); // => 1234
System.out.println(user.getSalary()); // => 5000
System.out.println(user.getRoleDto()); // => null
System.out.println(user.getAge()); // => 24
userService.save(user);
return ResponseEntity.ok().body("insert done");
} catch (Exception e) {
return ResponseEntity.badRequest().body(e.getMessage());
}
}
All properties print their value except the user.getRoleDto(), it always null. But, when I try to use this (below code) in the controller, it print the whole object exactly like the input object.
#RequestMapping(value="/signup", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> saveUser(HttpEntity<String> httpEntity){
try {
String json = httpEntity.getBody();
System.out.println(json);
return ResponseEntity.ok().body("insert done");
} catch (Exception e) {
return ResponseEntity.badRequest().body(e.getMessage());
}
}
Here is my User.java
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column
private String username;
#Column
#JsonIgnore
private String password;
#Column
private long salary;
#Column
private int age;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "role_id")
private Role role;
// getters and setters
Here is my Role.java
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "role_name", nullable = false)
private String roleName;
// getters and setters
Here is my UserDto.java
private String username;
private String password;
private int age;
private long salary;
private RoleDto roleDto;
Here is my RoleDto.java
private Long id;
private String roleName;
What went wrong here? Any help would be very helpful. Thanks!
UPDATE
Thanks to Burm87, I took the option 1 from his suggestions in the answer. But, somehow the spring still see role_id as null, even the value is printed now. Here is in the userServiceImpl:
#Override
public User save(UserDto user) throws Exception {
User newUser = new User();
BeanUtils.copyProperties(user, newUser, "password");
// above line is refer to [here][1].
newUser.setPassword(bcryptEncoder.encode(user.getPassword()));
try {
userDao.save(newUser);
} catch (Exception e) {
throw new Exception(e);
// this throw "Column role_id cannot be null"
}
return newUser;
}
But, if I use below code, the setRole method is not applicable since I define user.getRole() in the DTO as int but define newUser.setRole() in the User entity as Role. But if I change the setRole in User entity as int, then, how I can tell the spring about the ManyToOne relation between User and Role? Note: I think I just want to make the input parameter for role to be just an integer as provided above.
#Override
public User save(UserDto user) throws Exception {
User newUser = new User();
newUser.setUsername(user.getUsername());
newUser.setPassword(bcryptEncoder.encode(user.getPassword()));
newUser.setAge(user.getAge());
newUser.setSalary(user.getSalary());
newUser.setRole(user.getRole()); // here is the problem
try {
userDao.save(newUser);
} catch (Exception e) {
throw new Exception(e);
}
return newUser;
}
You have two options here:
1) you keep the request you have and you change this field roleDto in your DTO to be an Integer field named role (renaming getter and setter accordingly);
2) you keep your DTO as it is and you change your request sending:
{
"username": "name",
"password": "1234",
"age": 12,
"salary": 5000,
"roleDto": {
"id": 1,
"roleName": "your role name"
}
}
role is null, because In UserDTO you have RoleDto. So you need to rename "role" to "roleDto" as it is a complex object ,it will have its own json. Please replace it with the following Json and see it works. Please follow this tutorial for more understanding.
{
"username": "name",
"password": "1234",
"age": 12,
"salary": 5000,
"roleDto": {
"id":1
}
}
It's because in your json you have "role": 1 and in dto - user.getRoleDto(). There is a mismatch between names, so it cannot be properly mapped. Try changing field name from roleDto in UserDto into role.
I'm kinda new to writing REST endpoints thus this question.
I'm writing a REST endpoint that should support a form submission in iOS that registers an User.
This is my User class.
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long Id;
private String username;
private String email;
private String password;
}
This is the controller user signup signature that I've been asked to work with,
#RestController
public class RegistrationController {
#RequestMapping(value = "/user/signup",
method = RequestMethod.POST,
consumes = {"application/json"})
public ResponseEntity<?> showRegistrationForm(#RequestBody User user) {
try{
//persist the User
return new ResponseEntity(HttpStatus.OK);
}catch(Exception e){
}
return new ResponseEntity(HttpStatus.BAD_REQUEST);
}
}
The user object is provided to me using the following JSON payload,
{
"username": "Something",
"email": "Something",
"password": "password"
}
What I don't understand is how do I grab the fields posted from the form and convert them to the user in a POST request. Wouldn't I need to change the parameters to string, validate them and then compose the User object. Or just what is the right way of doing this.
Any help appreciated.
I have an ViewModel and put jsonannotation on some fields according this post of spring.io like below:
public class SurveyViewModel{
#JsonView(View.Summary.class)
private Long id;
#JsonView(View.Summary.class)
private String title;
private String description;
private String endDate;
//Here is getters & setters
}
When I retrieve data from my REST Controller, if return Type of my method is List, json-result is OK:
#RequestMapping(value = "/getAllGrid", method = RequestMethod.GET)
#JsonView(View.Summary.class)
#ResponseBody
public List<SurveyViewModel> getAll{
return ModelMapper.mapList(iSurveyService.getAll(), SurveyViewModel.class);
}
But when I apply paging on my result & change return type of this method to QueryResult, json-result is empty:
#RequestMapping(value = "/getAllGrid", method = RequestMethod.GET)
#JsonView(View.Summary.class)
#ResponseBody
public QueryResult<SurveyViewModel> search(String order, int pageNumber, int pageSize) {
return ModelMapper.mapQueryResult(iSurveyService.getAllGrid(new SearchOption("", order, pageNumber, pageSize)), SurveyViewModel.class);
}
When I apply paging on my result with above method, pageNumber, totalRecords & pageSize added to my json result and original-data add to entityList as inner json object, Here is myQueryResult in json format without apply #JsonView:
{
"pageNumber" : 0,
"totalRecords" : 1,
"pageSize" : 10,
"entityList" : [{
"id" : 1,
"title" : "survey1",
"description" : "...",
"endDate" : "2017/01/18",
},{
"id" : 2,
"title" : "survey2",
"description" : "...",
"endDate" : "2016/11/18",
}]
}
Now my question is, Is there any way to put #JsonView on Controller method with QueryResult returnType?
QueryResult is an object that I use for pagination, I solve my problem by putting #jsonView on properties of QueryResult class, like below:
public class QueryResult<T> {
#JsonView(View.Summary.class)
private int pageNumber;
#JsonView(View.Summary.class)
private int totalRecords;
#JsonView(View.Summary.class)
private int pageSize;
#JsonView(View.SummaryWithRecipients.class)
private List<T> entityList = new ArrayList<T>();
//Here is getters & setters
}
i have a problem with rest and method post on my controler i have this 2 class the first is user in my class user i have my class with the getters and setter and a default contructor because for the finally I would like use Hibernate .:
#Entity
#Table(name="Utilisateur") // mapping with hibernate (but not using in this situation)
public class User {
#Id
private long id;
#Column(name="nom")
private String nom;
#Column(name="prenom")
private String prenom;
#Column(name="admin")
private boolean admin;
#Column(name="actif")
private boolean actif;
#Column(name="logins")
private String logins;
#Column(name="email")
private String email;
#Column(name="naissance")
private String naissance;
#Column(name="pwd")
private String pwd;
#Column(name="compte")
private String compte;
public User(){
}
/*
with getter and setter.
*/
}
and my class controler (User controller) : is using for make the api principally post api .
#RestController
public class UserController {
#RequestMapping(
value="/api/greetings/post",
method = RequestMethod.POST,
consumes = MediaType.APPLICATION_JSON_VALUE,
produces=MediaType.APPLICATION_JSON_VALUE
)
#ResponseBody
public ResponseEntity<User> getByEmail(#RequestBody User user){
if(user==null){
return new ResponseEntity<User>(HttpStatus.INTERNAL_SERVER_ERROR);
}
return new ResponseEntity<User>(user, HttpStatus.OK);
}
and i get this erreur I am using postman for make the query and in parameter of my query I send this Json query :
{"id":"3","nom":"Gille","prenom":"Laurent","admin":"1","actif":"0","logins":"gilaur","email":""toto#hotmail.com,"naissance":"1990/09/09","pwd":"gal","compte":"autre"}
And i get this error :
{"timestamp":1457906727481,"status":415,"error":"Unsupported Media Type","exception":"org.springframework.web.HttpMediaTypeNotSupportedException","message":"Content type 'text/plain;charset=UTF-8' not supported","path":"/api/greetings/post/"}
Thank you
you are change headers content-type application/json in Postman because you try set text/plain
I am pretty new to mongo so this is probably just me not understanding how to setup collections. I have 2 domain objects and I have stripped them down to the basics for simplicity.
Post.java
#Document
public class Post {
#Id
private BigInteger id;
private String title;
private String body;
private String teaser;
private String slug;
private Date postedOn;
private Author author;
public Post(){
}
// getters & setters
}
Author.java
#Document
public class Author {
private BigInteger id;
private String firstName;
private String lastName;
private String email;
#DBRef
private List<Post> posts;
public Author(){
}
// getters and setters
}
I have a method that gets called to load some data into the database.
#PostConstruct
private void initDatabase(){
authorRepository.deleteAll();
Author dv = new Author();
dv.setFirstName("Dan");
dv.setLastName("Vega");
dv.setEmail("danvega#gmail.com");
authorRepository.save( dv );
postRepository.deleteAll();
Post post = new Post();
post.setTitle("Spring Data Rocks!");
post.setSlug("spring-data-rocks");
post.setTeaser("Post Teaser");
post.setBody("Post Body");
post.setPostedOn(new Date());
post.setAuthor(dv);
postRepository.save(post);
}
When I run mongo from the console and show collections I see both the post and author collections.
When I run db.post.find() the post contains the author object
{ "_id" : ObjectId("5666201fd4c6bcfd2f4caa90"), "_class" : "com.therealdanvega.domain.Post", "title" : "Spring Data Rocks!", "body" : "Post Body", "teaser" : "Post Teaser", "slug" : "spring-data-rocks", "postedOn" : ISODate("2015-12-08T00:11:11.090Z"), "author" : { "_id" : ObjectId("5666201fd4c6bcfd2f4caa8f"), "firstName" : "Dan", "lastName" : "Vega", "email" : "danvega#gmail.com" } }
But when I run db.author.find() I don't see the post collection in there.
{ "_id" : ObjectId("5666201fd4c6bcfd2f4caa8f"), "_class" : "com.therealdanvega.domain.Author", "firstName" : "Dan", "lastName" : "Vega", "email" : "danvega#gmail.com" }
Does anyone know what I am missing?
When you save you author object there is no post inside.
Create your Author, and create you post as you do.
Then set the post just created into the author's post list and save it.
This should do the trick
#PostConstruct
private void initDatabase(){
authorRepository.deleteAll();
Author dv = new Author();
dv.setFirstName("Dan");
dv.setLastName("Vega");
dv.setEmail("danvega#gmail.com");
authorRepository.save( dv );
postRepository.deleteAll();
Post post = new Post();
post.setTitle("Spring Data Rocks!");
post.setSlug("spring-data-rocks");
post.setTeaser("Post Teaser");
post.setBody("Post Body");
post.setPostedOn(new Date());
post.setAuthor(dv);
postRepository.save(post);
// add the code below
dv.posts = new ArrayList<Post>();
dv.posts.add(post);
authorRepository.save( dv );
}