I'm building a Server-Client Application, that communicates via a REST and HTTP. My Problem is, I try to Create a task. The JSON I sent from the client looks like this:
{
"taskType": "USER_STORY",
"headLine": "ew",
"taskText": "wewe",
"author": {
"id": 1,
"confirmed": false,
"email": "testlogin@test.de",
"userName": "Daniel",
"password": "test",
"creationTime": 1466843454239,
"assignedTasks": [
{
"id": 1,
"possibleTaskTypes": [
"USER_STORY",
"TECHNICAL_STORY",
"BUG"
],
"possibleTaskContainer": [
"PRODUCT_BACKLOG",
"SELECTED_BACKLOG",
"SPRINT"
],
"taskType": "USER_STORY",
"headLine": "123",
"taskText": "fsfd",
"possibleworkFlowStati": [
"START",
"READY_FOR_ESTIMATION",
"READY_FOR_SPRINT",
"OPEN",
"IN_PROGRESS",
"DONE"
],
"author": {
"id": 1,
"confirmed": false
},
"assignee": {
"id": 1,
"confirmed": false
},
"comments": [],
"creationTime": 1466843507898
}
],
"createdTasks": [
{
"id": 1,
"possibleTaskTypes": [
"USER_STORY",
"TECHNICAL_STORY",
"BUG"
],
"possibleTaskContainer": [
"PRODUCT_BACKLOG",
"SELECTED_BACKLOG",
"SPRINT"
],
"taskType": "USER_STORY",
"headLine": "123",
"taskText": "fsfd",
"possibleworkFlowStati": [
"START",
"READY_FOR_ESTIMATION",
"READY_FOR_SPRINT",
"OPEN",
"IN_PROGRESS",
"DONE"
],
"author": {
"id": 1,
"confirmed": false
},
"assignee": {
"id": 1,
"confirmed": false
},
"comments": [],
"creationTime": 1466843507898
}
]
},
"assignee": {
"id": 1,
"confirmed": false,
"email": "testlogin@test.de",
"userName": "Daniel",
"password": "test",
"creationTime": 1466843454239,
"assignedTasks": [
{
"id": 1,
"possibleTaskTypes": [
"USER_STORY",
"TECHNICAL_STORY",
"BUG"
],
"possibleTaskContainer": [
"PRODUCT_BACKLOG",
"SELECTED_BACKLOG",
"SPRINT"
],
"taskType": "USER_STORY",
"headLine": "123",
"taskText": "fsfd",
"possibleworkFlowStati": [
"START",
"READY_FOR_ESTIMATION",
"READY_FOR_SPRINT",
"OPEN",
"IN_PROGRESS",
"DONE"
],
"author": {
"id": 1,
"confirmed": false
},
"assignee": {
"id": 1,
"confirmed": false
},
"comments": [],
"creationTime": 1466843507898
}
],
"createdTasks": [
{
"id": 1
}
]
}
}
The Error-Message I get from the Server is this:
{
"title": "Message Not Readable",
"status": 400,
"detail": "Could not read document: N/A (through reference chain: de.name.supervisor.rest.domain.Task[\"author\"]->de.name.supervisor.rest.domain.User[\"assignedTasks\"]->java.util.HashSet[0]->de.name.supervisor.rest.domain.Task[\"author\"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: N/A (through reference chain: de.name.supervisor.rest.domain.Task[\"author\"]->de.name.supervisor.rest.domain.User[\"assignedTasks\"]->java.util.HashSet[0]->de.name.supervisor.rest.domain.Task[\"author\"])","timeStamp": 1466859943472,
"developerMessage": "org.springframework.http.converter.HttpMessageNotReadableException",
"errors": {}
}
I have no idea, what exactly doesn't work. When i post a single User, i have no problems.
The Example JSON generated by Swagger-UI is:
{
"comments": [
"string"
],
"creationTime": 0,
"possibleTaskContainer": [
"string"
],
"author": {
"password": "string",
"creationTime": 0,
"createdTasks": [
{}
],
"id": 0,
"userName": "string",
"confirmed": true,
"email": "string",
"assignedTasks": [
{}
]
},
"sprint": {
"inProgress": [
{}
],
"creationTime": 0,
"endDate": {
"dayOfWeek": "MONDAY",
"month": "JANUARY",
"year": 0,
"dayOfMonth": 0,
"era": {
"value": 0
},
"dayOfYear": 0,
"monthValue": 0,
"chronology": {
"id": "string",
"calendarType": "string"
},
"leapYear": true
},
"allTasks": [
{}
],
"sprintName": "string",
"id": 0,
"toDos": [
{}
],
"done": [
{}
],
"startDate": {
"dayOfWeek": "MONDAY",
"month": "JANUARY",
"year": 0,
"dayOfMonth": 0,
"era": {
"value": 0
},
"dayOfYear": 0,
"monthValue": 0,
"chronology": {
"id": "string",
"calendarType": "string"
},
"leapYear": true
}
},
"taskContainer": "string",
"headLine": "string",
"taskType": "string",
"id": 0,
"possibleTaskTypes": [
"string"
],
"assignee": {
"password": "string",
"creationTime": 0,
"createdTasks": [
{}
],
"id": 0,
"userName": "string",
"confirmed": true,
"email": "string",
"assignedTasks": [
{}
]
},
"possibleworkFlowStati": [
"string"
],
"taskText": "string",
"status": "string"
}
Is perhaps the Problem that assingee and user objects in the JSON sent by the client have only the id and confirmed fields? If this would be the reason then would this mean my controller doesn't work. Therefore here the Controller Method for the Post Request:
public HttpResponse postTask(Task task)throws ClientProtocolException, IOException{
HttpClient client = HttpClients.createDefault();
HttpPost post = new HttpPost(TASK_URI_V1);
Gson gson = new Gson();
String json = gson.toJson(task);
logger.info("Request-Body created: "+json);
post.setEntity(new StringEntity(json));
post.setHeader("Content-type", "application/json");
HttpResponse response = client.execute(post);
logger.info("Response from Web-Service after executing postTask request: "+response.getStatusLine().toString());
logger.info("Response Head from Web-Service after executing postTask request: "+response.toString());
logger.info("Response Body from Web-Service after executing postTask request: "+RestControllerUtils.getResponseBodyAsString(response));
return response;
}
And here the user-Model of the Client:
@JsonIgnoreProperties(ignoreUnknown = true)
public class User {
public User(){};
public User(int id){
setId(new Long(id));
}
private Long id;
private boolean confirmed;
private String email;
private String userName;
private String password;
private Long creationTime;
private Set<Task> assignedTasks;
private Set<Task> createdTasks;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public boolean isConfirmed() {
return confirmed;
}
public void setConfirmed(boolean confirmed) {
this.confirmed = confirmed;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Long getCreationTime() {
return creationTime;
}
public void setCreationTime(Long creationTime) {
this.creationTime = creationTime;
}
public Set<Task> getAssignedTasks() {
return assignedTasks;
}
public void setAssignedTasks(Set<Task> assignedTasks) {
this.assignedTasks = assignedTasks;
}
public void addAssignedTasks(Task task){
addAssignedTasks(task,true);
}
void addAssignedTasks(Task task, boolean set){
if(task != null){
getAssignedTasks().add(task);
if(set){
task.setAssignee(this);
}
}
}
public void removeAssidnedTask(Task task) {
getAssignedTasks().remove(task);
task.setAssignee(null);;
}
public Set<Task> getCreatedTasks() {
return createdTasks;
}
public void setCreatedTasks(Set<Task> createdTasks) {
this.createdTasks = createdTasks;
}
public void addCreatedTask(Task task){
addCreatedTask(task,true);
}
void addCreatedTask(Task task, boolean set){
if(task != null){
getCreatedTasks().add(task);
if(set){
task.setAuthor(this);
}
}
}
public void removeCreatedTask(Task task) {
getCreatedTasks().remove(task);
task.setAuthor(null);
}
}
And the User-Model of the Server:
@Entity
@Table(name="User")
@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class,property="@id", scope = User.class)
public class User {
@Id
@GeneratedValue
@Column(name="USER_ID")
private Long id;
@Column(name="CONFIRMATION")
private boolean confirmed;
@Column(name = "EMAIL",nullable = false)
private String email;
@Column(name = "USERNAME",nullable = false)
@NotNull
private String userName;
@Column(name="PASSWORD",nullable = false)
@NotNull
private String password;
@Column(name="TIMESTAMP")
private Long creationTime;
@OneToMany(cascade={CascadeType.DETACH,CascadeType.MERGE,CascadeType.REFRESH }, mappedBy="author",fetch=FetchType.EAGER)
private Set<Task>assignedTasks;
@OneToMany(cascade={CascadeType.DETACH,CascadeType.MERGE,CascadeType.REFRESH }, mappedBy="assignee",fetch=FetchType.EAGER)
private Set<Task>createdTasks;
public User() {
}
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 getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Long getCreationTime() {
return creationTime;
}
public void setCreationTime(Long creationTime) {
this.creationTime = creationTime;
}
public boolean isConfirmed() {
return confirmed;
}
public void setConfirmed(boolean confirmed) {
this.confirmed = confirmed;
}
public Set<Task> getAssignedTasks() {
return assignedTasks;
}
public void setAssignedTasks(Set<Task> assignedTasks) {
this.assignedTasks = assignedTasks;
}
public void addAssignedTasks(Task task){
addAssignedTasks(task,true);
}
void addAssignedTasks(Task task, boolean set){
if(task != null){
getAssignedTasks().add(task);
if(set){
task.setAssignee(this);
}
}
}
public void removeAssidnedTask(Task task) {
getAssignedTasks().remove(task);
task.setAssignee(null);;
}
public Set<Task> getCreatedTasks() {
return createdTasks;
}
public void setCreatedTasks(Set<Task> createdTasks) {
this.createdTasks = createdTasks;
}
public void addCreatedTask(Task task){
addCreatedTask(task,true);
}
void addCreatedTask(Task task, boolean set){
if(task != null){
getCreatedTasks().add(task);
if(set){
task.setAuthor(this);
}
}
}
public void removeCreatedTask(Task task) {
getCreatedTasks().remove(task);
task.setAuthor(null);
}
@Override
public String toString() {
return "User [id=" + id + ", confirmed=" + confirmed + ", email=" + email + ", userName=" + userName
+ ", password=" + password + "]";
}
}
The Task Class of the Server:
@Entity
@Table(name="Task")
//@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class,property="@id", scope = Task.class)
public class Task {
@Id
@GeneratedValue
@Column(name="TASK_ID")
private Long id;
@Transient
private List<String> possibleTaskTypes = TaskType.getTaskTypesAsString();
@Transient
private List<String>possibleTaskContainer = TaskContainer.getTaskContainerAsString();
@Column(name="TASK_Container")
private String taskContainer;
@Column(name="TASK_TYPE")
private String taskType;
@Column(name="HEAD_LINE")
private String headLine;
@Column(name="TASK_TEXT")
private String taskText;
@Transient
private List<String> possibleworkFlowStati = WorkFlowStatus.getWorkFlowsStatiAsString();
@Column(name="WORKFLOW_STATUS")
private String status;
@ManyToOne(cascade = {CascadeType.DETACH,CascadeType.MERGE,CascadeType.REFRESH })
private User author;
@ManyToOne(cascade = {CascadeType.DETACH,CascadeType.MERGE,CascadeType.REFRESH }) //TODO Check wether remove too.
private User assignee;
@Column(name="COMMENTS")
@ElementCollection(targetClass=String.class)
private List<String>comments;
@ManyToOne(cascade=CascadeType.ALL)
private Sprint sprint;
@Column(name="TIMESTAMP")
private Long creationTime;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getHeadLine() {
return headLine;
}
public void setHeadLine(String headLine) {
this.headLine = headLine;
}
public String getTaskText() {
return taskText;
}
public void setTaskText(String taskText) {
this.taskText = taskText;
}
public User getAuthor() {
return author;
}
public void setAuthor(User author) {
setAuthor(author, true);
}
void setAuthor(User author, boolean add){
this.author = author;
if(author !=null&&add){
author.addCreatedTask(this, false);
}
}
public User getAssignee() {
return assignee;
}
public void setAssignee(User assignee) {
setAssignee(assignee,true);
}
void setAssignee(User assignee, boolean add){
this.assignee = assignee;
if(assignee != null && add){
assignee.addAssignedTasks(this,false);
}
}
public List<String> getComments() {
return comments;
}
public void setComments(List<String> comments) {
this.comments = comments;
}
public Sprint getSprint() {
return sprint;
}
public void setSprint(Sprint sprint) {
this.sprint = sprint;
}
public Long getCreationTime() {
return creationTime;
}
public void setCreationTime(Long creationTime) {
this.creationTime = creationTime;
}
public String getTaskType() {
return taskType;
}
public void setTaskType(String taskType) {
this.taskType = taskType;
}
public List<String> getPossibleTaskTypes() {
return possibleTaskTypes;
}
public void setPossibleTaskTypes(List<String> possibleTaskTypes) {
this.possibleTaskTypes = possibleTaskTypes;
}
public List<String> getPossibleworkFlowStati() {
return possibleworkFlowStati;
}
public void setPossibleworkFlowStati(List<String> possibleworkFlowStati) {
this.possibleworkFlowStati = possibleworkFlowStati;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public List<String> getPossibleTaskContainer() {
return possibleTaskContainer;
}
public void setPossibleTaskContainer(List<String> possibleTaskContainer) {
this.possibleTaskContainer = possibleTaskContainer;
}
public String getTaskContainer() {
return taskContainer;
}
public void setTaskContainer(String taskContainer) {
this.taskContainer = taskContainer;
}
@Override
public String toString() {
return "Task [id=" + id + ", possibleTaskTypes=" + possibleTaskTypes + ", possibleTaskContainer="
+ possibleTaskContainer + ", taskContainer=" + taskContainer + ", taskType=" + taskType + ", headLine="
+ headLine + ", taskText=" + taskText + ", possibleworkFlowStati=" + possibleworkFlowStati + ", status="
+ status + ", author=" + author + ", assignee=" + assignee + ", comments=" + comments + ", sprint="
+ sprint + ", creationTime=" + creationTime + "]";
}
}