How do I deserialize a JSON object onto an implementation of an interface based on its key-value pairs?












0















I am setting up a controller for a Spring Boot application. I want the controller to produce an instance of an implementation of an interface based on the key-value pairs of the incoming JSON string.



The interface:



public interface ShoppableItem {}


Implementation 1:



public class GroceryItem implements ShoppableItem {

@JsonProperty("transactionId")
private Long transactionId;

@JsonProperty
@NotNull
private String itemName;

@JsonProperty
@NotNull
private Float weight;
}


Implementation 2:



public class ClothingItem implements ShoppableItem {

@JsonProperty("transactionId")
private Long transactionId;

@JsonProperty
@NotNull
private String itemName;

}


(Note: If a weight is provided, it is a grocery item and it cannot be null or "". If a weight is not provided, then it is a clothing item).



Controller



@Controller
public class Total {

@PostMapping(value = "total")
@ResponseStatus(HttpStatus.ACCEPTED)
public String tester(@Valid @RequestBody ShoppableItem shoppableItem) {
return shoppableItem.toString();
}
}


JSON body



{
"transactionId" : "123",
"itemName" : "whatever"
}


The desired result was to create an instance of type ClothingItem. When I tried doing this, I get the following exception:




org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Can not construct instance of com.test.controllers.Models.ShoppableItem: abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of com.test.controllers.Models.ShoppableItem: abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information




Is this a feature I am implementing incorrectly? I understand this may not be the best approach, as it would be easier to just create 2 endpoints to handle each case.










share|improve this question





























    0















    I am setting up a controller for a Spring Boot application. I want the controller to produce an instance of an implementation of an interface based on the key-value pairs of the incoming JSON string.



    The interface:



    public interface ShoppableItem {}


    Implementation 1:



    public class GroceryItem implements ShoppableItem {

    @JsonProperty("transactionId")
    private Long transactionId;

    @JsonProperty
    @NotNull
    private String itemName;

    @JsonProperty
    @NotNull
    private Float weight;
    }


    Implementation 2:



    public class ClothingItem implements ShoppableItem {

    @JsonProperty("transactionId")
    private Long transactionId;

    @JsonProperty
    @NotNull
    private String itemName;

    }


    (Note: If a weight is provided, it is a grocery item and it cannot be null or "". If a weight is not provided, then it is a clothing item).



    Controller



    @Controller
    public class Total {

    @PostMapping(value = "total")
    @ResponseStatus(HttpStatus.ACCEPTED)
    public String tester(@Valid @RequestBody ShoppableItem shoppableItem) {
    return shoppableItem.toString();
    }
    }


    JSON body



    {
    "transactionId" : "123",
    "itemName" : "whatever"
    }


    The desired result was to create an instance of type ClothingItem. When I tried doing this, I get the following exception:




    org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Can not construct instance of com.test.controllers.Models.ShoppableItem: abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of com.test.controllers.Models.ShoppableItem: abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information




    Is this a feature I am implementing incorrectly? I understand this may not be the best approach, as it would be easier to just create 2 endpoints to handle each case.










    share|improve this question



























      0












      0








      0








      I am setting up a controller for a Spring Boot application. I want the controller to produce an instance of an implementation of an interface based on the key-value pairs of the incoming JSON string.



      The interface:



      public interface ShoppableItem {}


      Implementation 1:



      public class GroceryItem implements ShoppableItem {

      @JsonProperty("transactionId")
      private Long transactionId;

      @JsonProperty
      @NotNull
      private String itemName;

      @JsonProperty
      @NotNull
      private Float weight;
      }


      Implementation 2:



      public class ClothingItem implements ShoppableItem {

      @JsonProperty("transactionId")
      private Long transactionId;

      @JsonProperty
      @NotNull
      private String itemName;

      }


      (Note: If a weight is provided, it is a grocery item and it cannot be null or "". If a weight is not provided, then it is a clothing item).



      Controller



      @Controller
      public class Total {

      @PostMapping(value = "total")
      @ResponseStatus(HttpStatus.ACCEPTED)
      public String tester(@Valid @RequestBody ShoppableItem shoppableItem) {
      return shoppableItem.toString();
      }
      }


      JSON body



      {
      "transactionId" : "123",
      "itemName" : "whatever"
      }


      The desired result was to create an instance of type ClothingItem. When I tried doing this, I get the following exception:




      org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Can not construct instance of com.test.controllers.Models.ShoppableItem: abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of com.test.controllers.Models.ShoppableItem: abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information




      Is this a feature I am implementing incorrectly? I understand this may not be the best approach, as it would be easier to just create 2 endpoints to handle each case.










      share|improve this question
















      I am setting up a controller for a Spring Boot application. I want the controller to produce an instance of an implementation of an interface based on the key-value pairs of the incoming JSON string.



      The interface:



      public interface ShoppableItem {}


      Implementation 1:



      public class GroceryItem implements ShoppableItem {

      @JsonProperty("transactionId")
      private Long transactionId;

      @JsonProperty
      @NotNull
      private String itemName;

      @JsonProperty
      @NotNull
      private Float weight;
      }


      Implementation 2:



      public class ClothingItem implements ShoppableItem {

      @JsonProperty("transactionId")
      private Long transactionId;

      @JsonProperty
      @NotNull
      private String itemName;

      }


      (Note: If a weight is provided, it is a grocery item and it cannot be null or "". If a weight is not provided, then it is a clothing item).



      Controller



      @Controller
      public class Total {

      @PostMapping(value = "total")
      @ResponseStatus(HttpStatus.ACCEPTED)
      public String tester(@Valid @RequestBody ShoppableItem shoppableItem) {
      return shoppableItem.toString();
      }
      }


      JSON body



      {
      "transactionId" : "123",
      "itemName" : "whatever"
      }


      The desired result was to create an instance of type ClothingItem. When I tried doing this, I get the following exception:




      org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Can not construct instance of com.test.controllers.Models.ShoppableItem: abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of com.test.controllers.Models.ShoppableItem: abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information




      Is this a feature I am implementing incorrectly? I understand this may not be the best approach, as it would be easier to just create 2 endpoints to handle each case.







      java json spring-boot jackson






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Dec 29 '18 at 11:35









      Thomas Fritsch

      5,111122033




      5,111122033










      asked Dec 29 '18 at 8:41









      John DoeJohn Doe

      134




      134
























          1 Answer
          1






          active

          oldest

          votes


















          0














          You can achieve this by adding a static factory method
          (annotated with @JsonCreator) to your ShoppableItem Interface.
          Note that you need to annotate all of its arguments with @JsonProperty
          so that Jackson will know how to map the JSON properties to method arguments.



          public interface ShoppableItem {

          @JsonCreator
          public static ShoppableItem create(@JsonProperty("transactionId") Long transactionId,
          @JsonProperty("itemName") String itemName,
          @JsonProperty("weight") Float weight) {
          if (weight == null)
          return new ClothingItem(transactionId, itemName);
          else
          return new GroceryItem(transactionId, itemName, weight);
          }
          }


          Then Jackson will use that method when deserializing a ShoppableItem.






          share|improve this answer

























            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53968033%2fhow-do-i-deserialize-a-json-object-onto-an-implementation-of-an-interface-based%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            0














            You can achieve this by adding a static factory method
            (annotated with @JsonCreator) to your ShoppableItem Interface.
            Note that you need to annotate all of its arguments with @JsonProperty
            so that Jackson will know how to map the JSON properties to method arguments.



            public interface ShoppableItem {

            @JsonCreator
            public static ShoppableItem create(@JsonProperty("transactionId") Long transactionId,
            @JsonProperty("itemName") String itemName,
            @JsonProperty("weight") Float weight) {
            if (weight == null)
            return new ClothingItem(transactionId, itemName);
            else
            return new GroceryItem(transactionId, itemName, weight);
            }
            }


            Then Jackson will use that method when deserializing a ShoppableItem.






            share|improve this answer






























              0














              You can achieve this by adding a static factory method
              (annotated with @JsonCreator) to your ShoppableItem Interface.
              Note that you need to annotate all of its arguments with @JsonProperty
              so that Jackson will know how to map the JSON properties to method arguments.



              public interface ShoppableItem {

              @JsonCreator
              public static ShoppableItem create(@JsonProperty("transactionId") Long transactionId,
              @JsonProperty("itemName") String itemName,
              @JsonProperty("weight") Float weight) {
              if (weight == null)
              return new ClothingItem(transactionId, itemName);
              else
              return new GroceryItem(transactionId, itemName, weight);
              }
              }


              Then Jackson will use that method when deserializing a ShoppableItem.






              share|improve this answer




























                0












                0








                0







                You can achieve this by adding a static factory method
                (annotated with @JsonCreator) to your ShoppableItem Interface.
                Note that you need to annotate all of its arguments with @JsonProperty
                so that Jackson will know how to map the JSON properties to method arguments.



                public interface ShoppableItem {

                @JsonCreator
                public static ShoppableItem create(@JsonProperty("transactionId") Long transactionId,
                @JsonProperty("itemName") String itemName,
                @JsonProperty("weight") Float weight) {
                if (weight == null)
                return new ClothingItem(transactionId, itemName);
                else
                return new GroceryItem(transactionId, itemName, weight);
                }
                }


                Then Jackson will use that method when deserializing a ShoppableItem.






                share|improve this answer















                You can achieve this by adding a static factory method
                (annotated with @JsonCreator) to your ShoppableItem Interface.
                Note that you need to annotate all of its arguments with @JsonProperty
                so that Jackson will know how to map the JSON properties to method arguments.



                public interface ShoppableItem {

                @JsonCreator
                public static ShoppableItem create(@JsonProperty("transactionId") Long transactionId,
                @JsonProperty("itemName") String itemName,
                @JsonProperty("weight") Float weight) {
                if (weight == null)
                return new ClothingItem(transactionId, itemName);
                else
                return new GroceryItem(transactionId, itemName, weight);
                }
                }


                Then Jackson will use that method when deserializing a ShoppableItem.







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Dec 29 '18 at 11:40

























                answered Dec 29 '18 at 11:25









                Thomas FritschThomas Fritsch

                5,111122033




                5,111122033






























                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53968033%2fhow-do-i-deserialize-a-json-object-onto-an-implementation-of-an-interface-based%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Monofisismo

                    Angular Downloading a file using contenturl with Basic Authentication

                    Olmecas