Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lombok generated constructor not found for deserialization on POST requests [DATAREST-884] #1254

Open
spring-projects-issues opened this issue Sep 6, 2016 · 5 comments
Assignees

Comments

@spring-projects-issues
Copy link

@spring-projects-issues spring-projects-issues commented Sep 6, 2016

Kai Tödter opened DATAREST-884 and commented

With Spring Boot 1.3.7 the following is working, with Spring Boot 1.4.0 not anymore:
You find all the examples in this report at https://github.com/toedter/chatty/
Branches:
master -> Spring Boot 1.3.7 => working
Spring-Boot-1.4.0 -> Spring Boot 1.4.0 => not working

Consider 2 REST resources with repositories: User and ChatMessage
ChatMessage has a relation to user:
@ManyToOne
private User author;

With Spring Boot 1.3.7 it was possible to create a new ChatMessage including a relation to an existing user with one POST request, when http://localhost:8080/api/users/toedter_k points to a valid User resource :

curl 'http://localhost:8080/api/messages' -i -X POST -H 'Content-Type: application/hal+json' -d '{"author":"http://localhost:8080/api/users/toedter_k","text":"Hello!"}'

This call gives the following error when using Spring Boot 1.4.0:
o.s.d.r.w.RepositoryRestExceptionHandler : Could not read document: Can not construct instance of com.toedter.chatty.server.boot.user.User: no String-argument constructor/factory method to deserialize from String value ('http://localhost:8080/api/users/toedter_k')

You find the corresponding test (Spring Restdocs) at
https://github.com/toedter/chatty/blob/master/subprojects/com.toedter.chatty.server.boot/src/test/java/com/toedter/chatty/server/boot/ApiDocumentation.java

    @Test
    public void messagesCreateExample() throws Exception {
        Map<String, String> user = new HashMap<String, String>();
        user.put("id", "toedter_k");
        user.put("fullName", "toedter_k");
        user.put("email", "kai@toedter.com");

        String userLocation = this.mockMvc
                .perform(
                        post("/api/users").contentType(MediaTypes.HAL_JSON).content(
                                this.objectMapper.writeValueAsString(user)))
                .andExpect(status().isCreated()).andReturn().getResponse()
                .getHeader("Location");

        Map<String, Object> chatMessage = new HashMap<String, Object>();
        chatMessage.put("text", "Hello!");
        chatMessage.put("author", userLocation);

        this.mockMvc.perform(
                post("/api/messages").contentType(MediaTypes.HAL_JSON).content(
                        this.objectMapper.writeValueAsString(chatMessage))).andExpect(
                status().isCreated())
                .andDo(document("messages-create-example",
                        requestFields(
                                fieldWithPath("text").description("The text of the chat message"),
                                fieldWithPath("author").description("The author of the chat message. This must be the URL to an existing user resource."))));
    }

Affects: 2.5.2 (Hopper SR2), 2.5.3 (Hopper SR3)

1 votes, 4 watchers

@spring-projects-issues
Copy link
Author

@spring-projects-issues spring-projects-issues commented Sep 12, 2016

Oliver Drotbohm commented

This seems to be an issue between Jackson and Lombok. @AllArgsConstructor generates explicit constructor name annotations that cause trouble as fro some reason that causes Jackson to treat the properties slightly different and not apply our registered deserialization customization. You can work around this by changing @AllArgsConstructor to @AllArgsConstructor(suppressConstructorProperties = true). That makes your test go green for me.

I've already filed a related ticket (same effect but slightly different setup) here

@spring-projects-issues
Copy link
Author

@spring-projects-issues spring-projects-issues commented Sep 12, 2016

Kai Tödter commented

Thanks, Oliver.
@AllArgsConstructor(suppressConstructorProperties = true) works like a charm!

@spring-projects-issues
Copy link
Author

@spring-projects-issues spring-projects-issues commented Oct 3, 2016

Kai Tödter commented

With Spring Boot 1.4.1 @AllArgsConstructor is working again

@spring-projects-issues
Copy link
Author

@spring-projects-issues spring-projects-issues commented Jan 5, 2017

Robert Rackl commented

I have the same problem. I am expsoing a JpaRepositry as spring-data-rest-hateoas REST service with the "@RepositoryRestResource" anotation.

I also have the parent-child relation between an "idea" in a given "area", ie. idea references area @ManyToOne.

When I try to POST a new idea that references an already existing area like this

{
   "title": "Inserted Idea",
   "description": "Very nice description",
   "area": "/liquido/v2/areas/2"
}

I also get the error message:

Can not construct instance of org.doogie.liquido.model.AreaModel: no String-argument constructor/factory method to deserialize from String value ('/liquido/v2/areas/2')

SOLVED!

The solution is as you mentioned. But interestingly you have to add the (suppressConstructorProperties = true) to the Idea entity. Not the AreaModel as the error message would point to. So you have to suppress Lombok's constructor property on the child entity!

@Data
@Entity
@NoArgsConstructor
@RequiredArgsConstructor(suppressConstructorProperties = true)
public class IdeaModel {
  [...]
}

SideRemark: It works the same with Lomboks AllArgsConstructor or RequiredArgsConstructor

@spring-projects-issues
Copy link
Author

@spring-projects-issues spring-projects-issues commented Jan 5, 2017

Robert Rackl commented

I think this is related: https://jira.spring.io/browse/DATAREST-687

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants
You can’t perform that action at this time.