Reputation: 4607
Spring Boot
version 2.1.6
.
I have User
class :
@Data
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
Long userID;
String eMail;
public User()
{
}
}
And a LoginCredential
class :
@Data
@Entity
public class LoginCredential {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
Long userID;
String eMail;
String passwordHash;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "id", referencedColumnName = "id")
User user;
public LoginCredential()
{
}
}
Shouldn't it create an instance of User
when I create an instance of LoginCredential
.
Cause I run this command : curl -X POST -H "Content-Type: application/json" -d "{ \"email\": \"a\", \"passwordHash\": \"b\" }" http://localhost:8080/login
And I got an instance of LoginCredential
but not of an User
.
Response :
{"userID":1,"passwordHash":"b","user":null,"email":"a"}
And then I run this command : curl -X POST -H "Content-Type: application/json" -d "{ \"email\": \"c\", \"passwordHash\": \"d\" ,\"user\":{}}" http://localhost:8080/login
And what I got is nothing, not of same ID.
Response :
{"userID":2,"passwordHash":"d","user":{"userID":3,"email":null},"email":"c"}
Am I missing something ? How this can be resolved ?
LoginCredentialController
partially :
@PostMapping("/login")
LoginCredential newLoginCredential(@RequestBody LoginCredential newLoginCredential)
{
return repository.save(newLoginCredential);
}
My pom.xml
Upvotes: 2
Views: 7003
Reputation: 4607
Here is the solution, I later asked another question and found out an answer
You have three problems
cascade
option to trigger User
entity creation from LoginCredential
save.@MapsId
annotation on User
so that they share the same id, otherwise LoginCredential
and its created User
will have different id values for both of them has @GeneratedValue(strategy = GenerationType.AUTO)
on their @Id
columnsTo fix all you need to change your entities to below (I also removed some useless annotations and values);
@Data
@Entity
public class User {
@Id
Long userID;
@JsonBackReference
@MapsId
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "userID", referencedColumnName = "userID")
@ToString.Exclude
private LoginCredential loginCredential;
}
and
@Data
@Entity
public class LoginCredential {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long userID;
String eMail;
String passwordHash;
@JsonManagedReference
@OneToOne(mappedBy = "loginCredential", fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
private User user;
}
Also need to set both sides of the relationship before finalizing your endpoint;
Optional.ofNullable(loginCredential.getUser())
.ifPresent(user -> user.setLoginCredential(loginCredential));
loginCredentialRepo.save(loginCredential);
Upvotes: 0
Reputation: 3453
@Data
@Entity
public class LoginCredential implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
Long credentailID;
String eMail;
String passwordHash;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "id", referencedColumnName = "id", nullable = false)
@OneToOne(fetch = FetchType.EAGER) //<-- EAGER is default, but try setting it explicitly
User user;
public LoginCredential()
{
}
}
@PostMapping("/login")
LoginCredential newLoginCredential(@RequestBody LoginCredential newLoginCredential)
{
LoginCredential saveResult = repository.save(newLoginCredential);
//load it again after saving
return repository.findbyId(saveResult.getuserId);
}
or better:
@PostMapping("/login")
ResponseEntity newLoginCredential(@RequestBody LoginCredential newLoginCredential)
{
try{
LoginCredential saveResult = repository.save(newLoginCredential);
//load it again after saving
LoginCredential loaded = repository.findbyId(saveResult.getuserId);
//if you set a breakpoint here, you should already see if it is working, if its ok here, then it might have to do with serilalization ( jackson )...
return new ResponseEntity<>(loaded,HttpStatus.OK);
}
catch (Exception e){
log.error(e.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
and, do you have a dependency for jackson ? -> its responsible for serializing the object to json ...
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
and this in your properties:
spring.jackson.serialization.indent_output=true
spring.jackson.default-property-inclusion=ALWAYS
hope that helps, cheers
Upvotes: 1