How to make controller endpoint to get two different objects in java spring?












3














I have a server built with java and spring.



What i am trying to do is that my controller with the same endpoint will get two different objects.



This is an example for what I mean:



I know I can do that:



  public class Option1{
private String name;
...
//getter and setter
}

public class Option2{
private Long id;
...
//getter and setter
}

@Controller
public class Controller{

@RequestMapping(value = "service/getData/option1", method = RequestMethod.POST)
@ResponseBody
public String searchProv(@ResponseBody Option1 data1){
return "option1"
}

@RequestMapping(value = "service/getData/option2", method = RequestMethod.POST)
@ResponseBody
public String searchProv(@ResponseBody Option2 data2){
return "option2"
}
}


but I wonder if it is possible to passing different json object to the same endpoint and do that:



 @Controller
public class Controller{

@RequestMapping(value = "service/getData", method = RequestMethod.POST)
@ResponseBody
public ResponseEntity<Any> getData(@ResponseBody Option1And2 data){
if(data instanceof Option1){
return return ResponseEntity<Any>(data.name,HttpStatus.OK)
}
if(data instanceof Option2){
return ResponseEntity<Any>(data.id,HttpStatus.OK)
}
return ResponseEntity<Any>("ok",HttpStatus.OK)
}


such that 'Option1And2' is generic object can be option1 or option2.



I tried to replace 'Option1And2' to 'Any' but it didn't went well because I get a list of keys and values










share|improve this question
























  • @AndrewTobilko no they don't have anything in common, totally different objects with different fields
    – JJ Redikes
    Nov 20 at 15:51










  • @AndrewTobilko this is only example, I have other goal to do with that for example if I'm working with WebSocket I would like to send a few different objects on the same channel. its easy to explain with controller and endpoint than WebSocket from the reason that WebSocket and endpoint works almost the same
    – JJ Redikes
    Nov 20 at 16:01












  • @AndrewTobilko 'option1and2' can either option1 or option2
    – JJ Redikes
    Nov 22 at 10:32










  • it doesn't work that way, you need to define a certain type as a method param
    – Andrew Tobilko
    Nov 22 at 10:55
















3














I have a server built with java and spring.



What i am trying to do is that my controller with the same endpoint will get two different objects.



This is an example for what I mean:



I know I can do that:



  public class Option1{
private String name;
...
//getter and setter
}

public class Option2{
private Long id;
...
//getter and setter
}

@Controller
public class Controller{

@RequestMapping(value = "service/getData/option1", method = RequestMethod.POST)
@ResponseBody
public String searchProv(@ResponseBody Option1 data1){
return "option1"
}

@RequestMapping(value = "service/getData/option2", method = RequestMethod.POST)
@ResponseBody
public String searchProv(@ResponseBody Option2 data2){
return "option2"
}
}


but I wonder if it is possible to passing different json object to the same endpoint and do that:



 @Controller
public class Controller{

@RequestMapping(value = "service/getData", method = RequestMethod.POST)
@ResponseBody
public ResponseEntity<Any> getData(@ResponseBody Option1And2 data){
if(data instanceof Option1){
return return ResponseEntity<Any>(data.name,HttpStatus.OK)
}
if(data instanceof Option2){
return ResponseEntity<Any>(data.id,HttpStatus.OK)
}
return ResponseEntity<Any>("ok",HttpStatus.OK)
}


such that 'Option1And2' is generic object can be option1 or option2.



I tried to replace 'Option1And2' to 'Any' but it didn't went well because I get a list of keys and values










share|improve this question
























  • @AndrewTobilko no they don't have anything in common, totally different objects with different fields
    – JJ Redikes
    Nov 20 at 15:51










  • @AndrewTobilko this is only example, I have other goal to do with that for example if I'm working with WebSocket I would like to send a few different objects on the same channel. its easy to explain with controller and endpoint than WebSocket from the reason that WebSocket and endpoint works almost the same
    – JJ Redikes
    Nov 20 at 16:01












  • @AndrewTobilko 'option1and2' can either option1 or option2
    – JJ Redikes
    Nov 22 at 10:32










  • it doesn't work that way, you need to define a certain type as a method param
    – Andrew Tobilko
    Nov 22 at 10:55














3












3








3


3





I have a server built with java and spring.



What i am trying to do is that my controller with the same endpoint will get two different objects.



This is an example for what I mean:



I know I can do that:



  public class Option1{
private String name;
...
//getter and setter
}

public class Option2{
private Long id;
...
//getter and setter
}

@Controller
public class Controller{

@RequestMapping(value = "service/getData/option1", method = RequestMethod.POST)
@ResponseBody
public String searchProv(@ResponseBody Option1 data1){
return "option1"
}

@RequestMapping(value = "service/getData/option2", method = RequestMethod.POST)
@ResponseBody
public String searchProv(@ResponseBody Option2 data2){
return "option2"
}
}


but I wonder if it is possible to passing different json object to the same endpoint and do that:



 @Controller
public class Controller{

@RequestMapping(value = "service/getData", method = RequestMethod.POST)
@ResponseBody
public ResponseEntity<Any> getData(@ResponseBody Option1And2 data){
if(data instanceof Option1){
return return ResponseEntity<Any>(data.name,HttpStatus.OK)
}
if(data instanceof Option2){
return ResponseEntity<Any>(data.id,HttpStatus.OK)
}
return ResponseEntity<Any>("ok",HttpStatus.OK)
}


such that 'Option1And2' is generic object can be option1 or option2.



I tried to replace 'Option1And2' to 'Any' but it didn't went well because I get a list of keys and values










share|improve this question















I have a server built with java and spring.



What i am trying to do is that my controller with the same endpoint will get two different objects.



This is an example for what I mean:



I know I can do that:



  public class Option1{
private String name;
...
//getter and setter
}

public class Option2{
private Long id;
...
//getter and setter
}

@Controller
public class Controller{

@RequestMapping(value = "service/getData/option1", method = RequestMethod.POST)
@ResponseBody
public String searchProv(@ResponseBody Option1 data1){
return "option1"
}

@RequestMapping(value = "service/getData/option2", method = RequestMethod.POST)
@ResponseBody
public String searchProv(@ResponseBody Option2 data2){
return "option2"
}
}


but I wonder if it is possible to passing different json object to the same endpoint and do that:



 @Controller
public class Controller{

@RequestMapping(value = "service/getData", method = RequestMethod.POST)
@ResponseBody
public ResponseEntity<Any> getData(@ResponseBody Option1And2 data){
if(data instanceof Option1){
return return ResponseEntity<Any>(data.name,HttpStatus.OK)
}
if(data instanceof Option2){
return ResponseEntity<Any>(data.id,HttpStatus.OK)
}
return ResponseEntity<Any>("ok",HttpStatus.OK)
}


such that 'Option1And2' is generic object can be option1 or option2.



I tried to replace 'Option1And2' to 'Any' but it didn't went well because I get a list of keys and values







java json spring generic-programming






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 21 at 17:36

























asked Nov 20 at 15:32









JJ Redikes

185




185












  • @AndrewTobilko no they don't have anything in common, totally different objects with different fields
    – JJ Redikes
    Nov 20 at 15:51










  • @AndrewTobilko this is only example, I have other goal to do with that for example if I'm working with WebSocket I would like to send a few different objects on the same channel. its easy to explain with controller and endpoint than WebSocket from the reason that WebSocket and endpoint works almost the same
    – JJ Redikes
    Nov 20 at 16:01












  • @AndrewTobilko 'option1and2' can either option1 or option2
    – JJ Redikes
    Nov 22 at 10:32










  • it doesn't work that way, you need to define a certain type as a method param
    – Andrew Tobilko
    Nov 22 at 10:55


















  • @AndrewTobilko no they don't have anything in common, totally different objects with different fields
    – JJ Redikes
    Nov 20 at 15:51










  • @AndrewTobilko this is only example, I have other goal to do with that for example if I'm working with WebSocket I would like to send a few different objects on the same channel. its easy to explain with controller and endpoint than WebSocket from the reason that WebSocket and endpoint works almost the same
    – JJ Redikes
    Nov 20 at 16:01












  • @AndrewTobilko 'option1and2' can either option1 or option2
    – JJ Redikes
    Nov 22 at 10:32










  • it doesn't work that way, you need to define a certain type as a method param
    – Andrew Tobilko
    Nov 22 at 10:55
















@AndrewTobilko no they don't have anything in common, totally different objects with different fields
– JJ Redikes
Nov 20 at 15:51




@AndrewTobilko no they don't have anything in common, totally different objects with different fields
– JJ Redikes
Nov 20 at 15:51












@AndrewTobilko this is only example, I have other goal to do with that for example if I'm working with WebSocket I would like to send a few different objects on the same channel. its easy to explain with controller and endpoint than WebSocket from the reason that WebSocket and endpoint works almost the same
– JJ Redikes
Nov 20 at 16:01






@AndrewTobilko this is only example, I have other goal to do with that for example if I'm working with WebSocket I would like to send a few different objects on the same channel. its easy to explain with controller and endpoint than WebSocket from the reason that WebSocket and endpoint works almost the same
– JJ Redikes
Nov 20 at 16:01














@AndrewTobilko 'option1and2' can either option1 or option2
– JJ Redikes
Nov 22 at 10:32




@AndrewTobilko 'option1and2' can either option1 or option2
– JJ Redikes
Nov 22 at 10:32












it doesn't work that way, you need to define a certain type as a method param
– Andrew Tobilko
Nov 22 at 10:55




it doesn't work that way, you need to define a certain type as a method param
– Andrew Tobilko
Nov 22 at 10:55












3 Answers
3






active

oldest

votes


















1














You should use JsonNode object.



for your example you should do this:



 @Controller
public class Controller{

@RequestMapping(value = "service/getData", method = RequestMethod.POST)
@ResponseBody
public ResponseEntity<Any> getData(@RequestBody JsonNode jsonNode){

ObjectMapper obj = new ObjectMapper();

if(jsonNode.has("name"){
Option1 result= obj.convertValue(jsonNode,Option1.class)
return ResponseEntity<Any>(result.name,HttpStatus.OK)
}

else {

Option2 result= obj.convertValue(jsonNode,Option2.class)
return ResponseEntity<Any>(result.id,HttpStatus.OK)
}

return ResponseEntity<Any>("ok",HttpStatus.OK)
}


the JsonNode and the ObjectMapper you should import from here:



import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.JsonNode;


this link should help you to understand better on JsonNode and give you more details.



and this link should help you with the convertValue from JsonNode to java object(POJO).






share|improve this answer

















  • 1




    thank you!!! that's exactly what I looked for
    – JJ Redikes
    Nov 27 at 13:06



















0














Seems like you want program itself to determine what type the option is.But before you do that,are you sure what is the difference between these two Object?



First is,what is the Option1And2 actually is?If the Option1And2 contains all the field of Option1 and Option2 but it's not the subclass of those,then probably the Option1And2 could be like:



@Data
public class Option1And2{
private String name;

private Long id;
}



  • If you have other limits like "one of them and only one of them has
    to be null",then you could determine it by this rule.

  • If you don't have any other limitation,then maybe you could add a new
    field as a flag.


In fact those code style are not recommend.If those two functions have different responsibilities,then maybe it's better to not mix them together.You will understand what I mean when you have to refactor these code.



If these two functions do have lots of things in common,maybe it's better for you to refactor the service logic instead of just combining two service roughly by creating a new param Option1And2.



By the way,what are you exactly want to do?Why do you want to merge those two object into one?






share|improve this answer































    0














    This is a good time to use inheritance and Java Generics. It is worth noting, if your controller has any dependencies such as a @Service or @Repository, then those too must be generic.



    enter image description here



    You might have a generic controller:



    abstract class GenericController<T> {

    public abstract GenericService<T> getService();

    @GetMapping
    public ResponseEntity<Iterable<T>> findAll() {

    return ResponseEntity.ok(getService().findAll());
    }

    @PostMapping
    public ResponseEntity<T> save(T entity) {

    return ResponseEntity.ok(getService().save(entity));
    }

    // @DeleteMapping, @PutMapping
    // These mappings will automatically be inherited by
    // the child class. So in the case of findAll(), the API
    // will have a GET mapping on /category as well as a GET
    // mapping on /product. So, by defining and annotating the
    // CRUD operations in the parent class, they will automatically
    // become available in all child classes.
    }

    @Controller
    @RequestMapping("/category")
    class CategoryContr extends GenericController<Category> {

    @Autowired CategoryServ serv;

    @Override
    public GenericService<Category> getService() {
    return serv;
    }
    }

    @Controller
    @RequestMapping("/product")
    class ProductContr extends GenericController<Product> {

    @Autowired ProductServ serv;

    @Override
    public GenericService<Product> getService() {
    return serv;
    }
    }


    You then have to have abstract versions of the dependencies. The services:



    abstract class GenericService<T> {

    public abstract GenericRepository<T> getRepository();

    public Iterable<T> findAll() {

    return getRepository().findAll();
    }

    public T save(T entity) {

    return getRepository().save(entity);
    }

    }

    @Service
    class CategoryServ extends GenericService<Category> {

    @Autowired CategoryRepo repo;

    @Override
    public GenericRepository<Category> getRepository() {
    return repo;
    }
    }

    @Service
    class ProductServ extends GenericService<Product> {

    @Autowired ProductRepo repo;

    @Override
    public GenericRepository<Product> getRepository() {
    return repo;
    }
    }


    Then, the services have their dependencies as well - the repositories:



    @NoRepositoryBean
    interface GenericRepository<T> extends JpaRepository<T, Long> {
    }

    @Repository
    interface CategoryRepo extends GenericRepository<Category> {
    }

    @Repository
    interface ProductRepo extends GenericRepository<Product> {
    }


    This was my first approach. It works very nicely. However, this does create a strong coupling between the business logic of each service and the generic service. The same holds true for the generic controller and its child classes. You can of course always override a particular CRUD operation. But, you must do this with care as you may created unexpected behavior. It is also worth noting that inheriting from classes that have methods that are annotated with @RequestMapping automatically exposes all of the annotated methods. This may be undesirable. For example, we may not want a delete option for categories, but we want it for products. To combat this, instead of annotating the method in the parent class, we can simply define it in the parent class, and override the desired CRUD operations with the added @RequestMapping annotation and then call the super class method.



    Another approach is using annotations.






    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%2f53396390%2fhow-to-make-controller-endpoint-to-get-two-different-objects-in-java-spring%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      1














      You should use JsonNode object.



      for your example you should do this:



       @Controller
      public class Controller{

      @RequestMapping(value = "service/getData", method = RequestMethod.POST)
      @ResponseBody
      public ResponseEntity<Any> getData(@RequestBody JsonNode jsonNode){

      ObjectMapper obj = new ObjectMapper();

      if(jsonNode.has("name"){
      Option1 result= obj.convertValue(jsonNode,Option1.class)
      return ResponseEntity<Any>(result.name,HttpStatus.OK)
      }

      else {

      Option2 result= obj.convertValue(jsonNode,Option2.class)
      return ResponseEntity<Any>(result.id,HttpStatus.OK)
      }

      return ResponseEntity<Any>("ok",HttpStatus.OK)
      }


      the JsonNode and the ObjectMapper you should import from here:



      import com.fasterxml.jackson.databind.ObjectMapper
      import com.fasterxml.jackson.databind.JsonNode;


      this link should help you to understand better on JsonNode and give you more details.



      and this link should help you with the convertValue from JsonNode to java object(POJO).






      share|improve this answer

















      • 1




        thank you!!! that's exactly what I looked for
        – JJ Redikes
        Nov 27 at 13:06
















      1














      You should use JsonNode object.



      for your example you should do this:



       @Controller
      public class Controller{

      @RequestMapping(value = "service/getData", method = RequestMethod.POST)
      @ResponseBody
      public ResponseEntity<Any> getData(@RequestBody JsonNode jsonNode){

      ObjectMapper obj = new ObjectMapper();

      if(jsonNode.has("name"){
      Option1 result= obj.convertValue(jsonNode,Option1.class)
      return ResponseEntity<Any>(result.name,HttpStatus.OK)
      }

      else {

      Option2 result= obj.convertValue(jsonNode,Option2.class)
      return ResponseEntity<Any>(result.id,HttpStatus.OK)
      }

      return ResponseEntity<Any>("ok",HttpStatus.OK)
      }


      the JsonNode and the ObjectMapper you should import from here:



      import com.fasterxml.jackson.databind.ObjectMapper
      import com.fasterxml.jackson.databind.JsonNode;


      this link should help you to understand better on JsonNode and give you more details.



      and this link should help you with the convertValue from JsonNode to java object(POJO).






      share|improve this answer

















      • 1




        thank you!!! that's exactly what I looked for
        – JJ Redikes
        Nov 27 at 13:06














      1












      1








      1






      You should use JsonNode object.



      for your example you should do this:



       @Controller
      public class Controller{

      @RequestMapping(value = "service/getData", method = RequestMethod.POST)
      @ResponseBody
      public ResponseEntity<Any> getData(@RequestBody JsonNode jsonNode){

      ObjectMapper obj = new ObjectMapper();

      if(jsonNode.has("name"){
      Option1 result= obj.convertValue(jsonNode,Option1.class)
      return ResponseEntity<Any>(result.name,HttpStatus.OK)
      }

      else {

      Option2 result= obj.convertValue(jsonNode,Option2.class)
      return ResponseEntity<Any>(result.id,HttpStatus.OK)
      }

      return ResponseEntity<Any>("ok",HttpStatus.OK)
      }


      the JsonNode and the ObjectMapper you should import from here:



      import com.fasterxml.jackson.databind.ObjectMapper
      import com.fasterxml.jackson.databind.JsonNode;


      this link should help you to understand better on JsonNode and give you more details.



      and this link should help you with the convertValue from JsonNode to java object(POJO).






      share|improve this answer












      You should use JsonNode object.



      for your example you should do this:



       @Controller
      public class Controller{

      @RequestMapping(value = "service/getData", method = RequestMethod.POST)
      @ResponseBody
      public ResponseEntity<Any> getData(@RequestBody JsonNode jsonNode){

      ObjectMapper obj = new ObjectMapper();

      if(jsonNode.has("name"){
      Option1 result= obj.convertValue(jsonNode,Option1.class)
      return ResponseEntity<Any>(result.name,HttpStatus.OK)
      }

      else {

      Option2 result= obj.convertValue(jsonNode,Option2.class)
      return ResponseEntity<Any>(result.id,HttpStatus.OK)
      }

      return ResponseEntity<Any>("ok",HttpStatus.OK)
      }


      the JsonNode and the ObjectMapper you should import from here:



      import com.fasterxml.jackson.databind.ObjectMapper
      import com.fasterxml.jackson.databind.JsonNode;


      this link should help you to understand better on JsonNode and give you more details.



      and this link should help you with the convertValue from JsonNode to java object(POJO).







      share|improve this answer












      share|improve this answer



      share|improve this answer










      answered Nov 27 at 12:24









      Tal Shani

      829




      829








      • 1




        thank you!!! that's exactly what I looked for
        – JJ Redikes
        Nov 27 at 13:06














      • 1




        thank you!!! that's exactly what I looked for
        – JJ Redikes
        Nov 27 at 13:06








      1




      1




      thank you!!! that's exactly what I looked for
      – JJ Redikes
      Nov 27 at 13:06




      thank you!!! that's exactly what I looked for
      – JJ Redikes
      Nov 27 at 13:06













      0














      Seems like you want program itself to determine what type the option is.But before you do that,are you sure what is the difference between these two Object?



      First is,what is the Option1And2 actually is?If the Option1And2 contains all the field of Option1 and Option2 but it's not the subclass of those,then probably the Option1And2 could be like:



      @Data
      public class Option1And2{
      private String name;

      private Long id;
      }



      • If you have other limits like "one of them and only one of them has
        to be null",then you could determine it by this rule.

      • If you don't have any other limitation,then maybe you could add a new
        field as a flag.


      In fact those code style are not recommend.If those two functions have different responsibilities,then maybe it's better to not mix them together.You will understand what I mean when you have to refactor these code.



      If these two functions do have lots of things in common,maybe it's better for you to refactor the service logic instead of just combining two service roughly by creating a new param Option1And2.



      By the way,what are you exactly want to do?Why do you want to merge those two object into one?






      share|improve this answer




























        0














        Seems like you want program itself to determine what type the option is.But before you do that,are you sure what is the difference between these two Object?



        First is,what is the Option1And2 actually is?If the Option1And2 contains all the field of Option1 and Option2 but it's not the subclass of those,then probably the Option1And2 could be like:



        @Data
        public class Option1And2{
        private String name;

        private Long id;
        }



        • If you have other limits like "one of them and only one of them has
          to be null",then you could determine it by this rule.

        • If you don't have any other limitation,then maybe you could add a new
          field as a flag.


        In fact those code style are not recommend.If those two functions have different responsibilities,then maybe it's better to not mix them together.You will understand what I mean when you have to refactor these code.



        If these two functions do have lots of things in common,maybe it's better for you to refactor the service logic instead of just combining two service roughly by creating a new param Option1And2.



        By the way,what are you exactly want to do?Why do you want to merge those two object into one?






        share|improve this answer


























          0












          0








          0






          Seems like you want program itself to determine what type the option is.But before you do that,are you sure what is the difference between these two Object?



          First is,what is the Option1And2 actually is?If the Option1And2 contains all the field of Option1 and Option2 but it's not the subclass of those,then probably the Option1And2 could be like:



          @Data
          public class Option1And2{
          private String name;

          private Long id;
          }



          • If you have other limits like "one of them and only one of them has
            to be null",then you could determine it by this rule.

          • If you don't have any other limitation,then maybe you could add a new
            field as a flag.


          In fact those code style are not recommend.If those two functions have different responsibilities,then maybe it's better to not mix them together.You will understand what I mean when you have to refactor these code.



          If these two functions do have lots of things in common,maybe it's better for you to refactor the service logic instead of just combining two service roughly by creating a new param Option1And2.



          By the way,what are you exactly want to do?Why do you want to merge those two object into one?






          share|improve this answer














          Seems like you want program itself to determine what type the option is.But before you do that,are you sure what is the difference between these two Object?



          First is,what is the Option1And2 actually is?If the Option1And2 contains all the field of Option1 and Option2 but it's not the subclass of those,then probably the Option1And2 could be like:



          @Data
          public class Option1And2{
          private String name;

          private Long id;
          }



          • If you have other limits like "one of them and only one of them has
            to be null",then you could determine it by this rule.

          • If you don't have any other limitation,then maybe you could add a new
            field as a flag.


          In fact those code style are not recommend.If those two functions have different responsibilities,then maybe it's better to not mix them together.You will understand what I mean when you have to refactor these code.



          If these two functions do have lots of things in common,maybe it's better for you to refactor the service logic instead of just combining two service roughly by creating a new param Option1And2.



          By the way,what are you exactly want to do?Why do you want to merge those two object into one?







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 21 at 6:15

























          answered Nov 21 at 6:06









          AokoQin

          794




          794























              0














              This is a good time to use inheritance and Java Generics. It is worth noting, if your controller has any dependencies such as a @Service or @Repository, then those too must be generic.



              enter image description here



              You might have a generic controller:



              abstract class GenericController<T> {

              public abstract GenericService<T> getService();

              @GetMapping
              public ResponseEntity<Iterable<T>> findAll() {

              return ResponseEntity.ok(getService().findAll());
              }

              @PostMapping
              public ResponseEntity<T> save(T entity) {

              return ResponseEntity.ok(getService().save(entity));
              }

              // @DeleteMapping, @PutMapping
              // These mappings will automatically be inherited by
              // the child class. So in the case of findAll(), the API
              // will have a GET mapping on /category as well as a GET
              // mapping on /product. So, by defining and annotating the
              // CRUD operations in the parent class, they will automatically
              // become available in all child classes.
              }

              @Controller
              @RequestMapping("/category")
              class CategoryContr extends GenericController<Category> {

              @Autowired CategoryServ serv;

              @Override
              public GenericService<Category> getService() {
              return serv;
              }
              }

              @Controller
              @RequestMapping("/product")
              class ProductContr extends GenericController<Product> {

              @Autowired ProductServ serv;

              @Override
              public GenericService<Product> getService() {
              return serv;
              }
              }


              You then have to have abstract versions of the dependencies. The services:



              abstract class GenericService<T> {

              public abstract GenericRepository<T> getRepository();

              public Iterable<T> findAll() {

              return getRepository().findAll();
              }

              public T save(T entity) {

              return getRepository().save(entity);
              }

              }

              @Service
              class CategoryServ extends GenericService<Category> {

              @Autowired CategoryRepo repo;

              @Override
              public GenericRepository<Category> getRepository() {
              return repo;
              }
              }

              @Service
              class ProductServ extends GenericService<Product> {

              @Autowired ProductRepo repo;

              @Override
              public GenericRepository<Product> getRepository() {
              return repo;
              }
              }


              Then, the services have their dependencies as well - the repositories:



              @NoRepositoryBean
              interface GenericRepository<T> extends JpaRepository<T, Long> {
              }

              @Repository
              interface CategoryRepo extends GenericRepository<Category> {
              }

              @Repository
              interface ProductRepo extends GenericRepository<Product> {
              }


              This was my first approach. It works very nicely. However, this does create a strong coupling between the business logic of each service and the generic service. The same holds true for the generic controller and its child classes. You can of course always override a particular CRUD operation. But, you must do this with care as you may created unexpected behavior. It is also worth noting that inheriting from classes that have methods that are annotated with @RequestMapping automatically exposes all of the annotated methods. This may be undesirable. For example, we may not want a delete option for categories, but we want it for products. To combat this, instead of annotating the method in the parent class, we can simply define it in the parent class, and override the desired CRUD operations with the added @RequestMapping annotation and then call the super class method.



              Another approach is using annotations.






              share|improve this answer




























                0














                This is a good time to use inheritance and Java Generics. It is worth noting, if your controller has any dependencies such as a @Service or @Repository, then those too must be generic.



                enter image description here



                You might have a generic controller:



                abstract class GenericController<T> {

                public abstract GenericService<T> getService();

                @GetMapping
                public ResponseEntity<Iterable<T>> findAll() {

                return ResponseEntity.ok(getService().findAll());
                }

                @PostMapping
                public ResponseEntity<T> save(T entity) {

                return ResponseEntity.ok(getService().save(entity));
                }

                // @DeleteMapping, @PutMapping
                // These mappings will automatically be inherited by
                // the child class. So in the case of findAll(), the API
                // will have a GET mapping on /category as well as a GET
                // mapping on /product. So, by defining and annotating the
                // CRUD operations in the parent class, they will automatically
                // become available in all child classes.
                }

                @Controller
                @RequestMapping("/category")
                class CategoryContr extends GenericController<Category> {

                @Autowired CategoryServ serv;

                @Override
                public GenericService<Category> getService() {
                return serv;
                }
                }

                @Controller
                @RequestMapping("/product")
                class ProductContr extends GenericController<Product> {

                @Autowired ProductServ serv;

                @Override
                public GenericService<Product> getService() {
                return serv;
                }
                }


                You then have to have abstract versions of the dependencies. The services:



                abstract class GenericService<T> {

                public abstract GenericRepository<T> getRepository();

                public Iterable<T> findAll() {

                return getRepository().findAll();
                }

                public T save(T entity) {

                return getRepository().save(entity);
                }

                }

                @Service
                class CategoryServ extends GenericService<Category> {

                @Autowired CategoryRepo repo;

                @Override
                public GenericRepository<Category> getRepository() {
                return repo;
                }
                }

                @Service
                class ProductServ extends GenericService<Product> {

                @Autowired ProductRepo repo;

                @Override
                public GenericRepository<Product> getRepository() {
                return repo;
                }
                }


                Then, the services have their dependencies as well - the repositories:



                @NoRepositoryBean
                interface GenericRepository<T> extends JpaRepository<T, Long> {
                }

                @Repository
                interface CategoryRepo extends GenericRepository<Category> {
                }

                @Repository
                interface ProductRepo extends GenericRepository<Product> {
                }


                This was my first approach. It works very nicely. However, this does create a strong coupling between the business logic of each service and the generic service. The same holds true for the generic controller and its child classes. You can of course always override a particular CRUD operation. But, you must do this with care as you may created unexpected behavior. It is also worth noting that inheriting from classes that have methods that are annotated with @RequestMapping automatically exposes all of the annotated methods. This may be undesirable. For example, we may not want a delete option for categories, but we want it for products. To combat this, instead of annotating the method in the parent class, we can simply define it in the parent class, and override the desired CRUD operations with the added @RequestMapping annotation and then call the super class method.



                Another approach is using annotations.






                share|improve this answer


























                  0












                  0








                  0






                  This is a good time to use inheritance and Java Generics. It is worth noting, if your controller has any dependencies such as a @Service or @Repository, then those too must be generic.



                  enter image description here



                  You might have a generic controller:



                  abstract class GenericController<T> {

                  public abstract GenericService<T> getService();

                  @GetMapping
                  public ResponseEntity<Iterable<T>> findAll() {

                  return ResponseEntity.ok(getService().findAll());
                  }

                  @PostMapping
                  public ResponseEntity<T> save(T entity) {

                  return ResponseEntity.ok(getService().save(entity));
                  }

                  // @DeleteMapping, @PutMapping
                  // These mappings will automatically be inherited by
                  // the child class. So in the case of findAll(), the API
                  // will have a GET mapping on /category as well as a GET
                  // mapping on /product. So, by defining and annotating the
                  // CRUD operations in the parent class, they will automatically
                  // become available in all child classes.
                  }

                  @Controller
                  @RequestMapping("/category")
                  class CategoryContr extends GenericController<Category> {

                  @Autowired CategoryServ serv;

                  @Override
                  public GenericService<Category> getService() {
                  return serv;
                  }
                  }

                  @Controller
                  @RequestMapping("/product")
                  class ProductContr extends GenericController<Product> {

                  @Autowired ProductServ serv;

                  @Override
                  public GenericService<Product> getService() {
                  return serv;
                  }
                  }


                  You then have to have abstract versions of the dependencies. The services:



                  abstract class GenericService<T> {

                  public abstract GenericRepository<T> getRepository();

                  public Iterable<T> findAll() {

                  return getRepository().findAll();
                  }

                  public T save(T entity) {

                  return getRepository().save(entity);
                  }

                  }

                  @Service
                  class CategoryServ extends GenericService<Category> {

                  @Autowired CategoryRepo repo;

                  @Override
                  public GenericRepository<Category> getRepository() {
                  return repo;
                  }
                  }

                  @Service
                  class ProductServ extends GenericService<Product> {

                  @Autowired ProductRepo repo;

                  @Override
                  public GenericRepository<Product> getRepository() {
                  return repo;
                  }
                  }


                  Then, the services have their dependencies as well - the repositories:



                  @NoRepositoryBean
                  interface GenericRepository<T> extends JpaRepository<T, Long> {
                  }

                  @Repository
                  interface CategoryRepo extends GenericRepository<Category> {
                  }

                  @Repository
                  interface ProductRepo extends GenericRepository<Product> {
                  }


                  This was my first approach. It works very nicely. However, this does create a strong coupling between the business logic of each service and the generic service. The same holds true for the generic controller and its child classes. You can of course always override a particular CRUD operation. But, you must do this with care as you may created unexpected behavior. It is also worth noting that inheriting from classes that have methods that are annotated with @RequestMapping automatically exposes all of the annotated methods. This may be undesirable. For example, we may not want a delete option for categories, but we want it for products. To combat this, instead of annotating the method in the parent class, we can simply define it in the parent class, and override the desired CRUD operations with the added @RequestMapping annotation and then call the super class method.



                  Another approach is using annotations.






                  share|improve this answer














                  This is a good time to use inheritance and Java Generics. It is worth noting, if your controller has any dependencies such as a @Service or @Repository, then those too must be generic.



                  enter image description here



                  You might have a generic controller:



                  abstract class GenericController<T> {

                  public abstract GenericService<T> getService();

                  @GetMapping
                  public ResponseEntity<Iterable<T>> findAll() {

                  return ResponseEntity.ok(getService().findAll());
                  }

                  @PostMapping
                  public ResponseEntity<T> save(T entity) {

                  return ResponseEntity.ok(getService().save(entity));
                  }

                  // @DeleteMapping, @PutMapping
                  // These mappings will automatically be inherited by
                  // the child class. So in the case of findAll(), the API
                  // will have a GET mapping on /category as well as a GET
                  // mapping on /product. So, by defining and annotating the
                  // CRUD operations in the parent class, they will automatically
                  // become available in all child classes.
                  }

                  @Controller
                  @RequestMapping("/category")
                  class CategoryContr extends GenericController<Category> {

                  @Autowired CategoryServ serv;

                  @Override
                  public GenericService<Category> getService() {
                  return serv;
                  }
                  }

                  @Controller
                  @RequestMapping("/product")
                  class ProductContr extends GenericController<Product> {

                  @Autowired ProductServ serv;

                  @Override
                  public GenericService<Product> getService() {
                  return serv;
                  }
                  }


                  You then have to have abstract versions of the dependencies. The services:



                  abstract class GenericService<T> {

                  public abstract GenericRepository<T> getRepository();

                  public Iterable<T> findAll() {

                  return getRepository().findAll();
                  }

                  public T save(T entity) {

                  return getRepository().save(entity);
                  }

                  }

                  @Service
                  class CategoryServ extends GenericService<Category> {

                  @Autowired CategoryRepo repo;

                  @Override
                  public GenericRepository<Category> getRepository() {
                  return repo;
                  }
                  }

                  @Service
                  class ProductServ extends GenericService<Product> {

                  @Autowired ProductRepo repo;

                  @Override
                  public GenericRepository<Product> getRepository() {
                  return repo;
                  }
                  }


                  Then, the services have their dependencies as well - the repositories:



                  @NoRepositoryBean
                  interface GenericRepository<T> extends JpaRepository<T, Long> {
                  }

                  @Repository
                  interface CategoryRepo extends GenericRepository<Category> {
                  }

                  @Repository
                  interface ProductRepo extends GenericRepository<Product> {
                  }


                  This was my first approach. It works very nicely. However, this does create a strong coupling between the business logic of each service and the generic service. The same holds true for the generic controller and its child classes. You can of course always override a particular CRUD operation. But, you must do this with care as you may created unexpected behavior. It is also worth noting that inheriting from classes that have methods that are annotated with @RequestMapping automatically exposes all of the annotated methods. This may be undesirable. For example, we may not want a delete option for categories, but we want it for products. To combat this, instead of annotating the method in the parent class, we can simply define it in the parent class, and override the desired CRUD operations with the added @RequestMapping annotation and then call the super class method.



                  Another approach is using annotations.







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Nov 21 at 17:31

























                  answered Nov 21 at 6:34









                  Jabari Dash

                  1,112617




                  1,112617






























                      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.





                      Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                      Please pay close attention to the following guidance:


                      • 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%2f53396390%2fhow-to-make-controller-endpoint-to-get-two-different-objects-in-java-spring%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

                      Create new schema in PostgreSQL using DBeaver

                      Deepest pit of an array with Javascript: test on Codility

                      Fotorealismo