This is more about Java than Dropwizard; but I have two resources in Dropwizard: CustomerResource and ApiResource.
In CustomerResource there is a createCustomer method which basically creates a new customer. The ApiResource will also create a new customer when a third party invokes a method inside of it, so this got me thinking about duplicate code and the best way to resolve it. I have a few approaches in mind; but first here are the classes for better clarity.
#Path("/internal")
public class CustomerResource{
private DBDao dbDao;
private AnotherAPI api;
//constructor for DI
public Response Create(#internalAuth CustomerPojo customerPojo) {
//logic to validate customerpojo
//logic to ensure user isn't a duplicate
//some other validation logic
//finally user creation/saving to DB
Return response.ok(200).build();
}
}
#Path("/external")
public class ApiResource{
private DBDao dbDao;
private AnotherAPI api;
//constructor for DI
public Response Create(#ExternalAuth PartialCustomerPojo partialCustomerPojo) {
//logic to validate PartialCustomerpojo
//supplement partialCustomerPojo
//logic to ensure user isn't a duplicate
//some other validation logic
//finally user creation/saving to DB
Return response.ok(200).build();
}
}
So two main differences are how the endpoint is called (authentication) and the payload provided.
The way I thought about removing duplicate code is to create a new concrete class that takes commonality from both resources and each of them instantiates a new class like this.
public class CommonClass{
private DBDao dbDao;
private AnotherAPI api;
//constructor for DI
public boolean Create (CommonPojo commonPojo) {
//logic to validate customerPojo
//logic to ensure user isn't a duplicate
//some other validation logic
//finally user creation/saving to DB
Return response.ok(200).build();
}
}
And now inside CustomerResource and ApiResource I simply do this.
CommonClass commonClass = new CommonClass(dbDao, api);
//create a new instance customerPojo or CommonPojo and call
commonClass.create(customerPojo);
Does this sound like a good strategy? Are there other concerns beyond duplication? These two resource methods can't be inside the same class either. Any best practice will be appreciated.
I think inheritance not the best solution.
Also I think that composition is much better. This can help you to use common code and easy to change it in other places where you need to change functionality.
Also it allows you to test all classes more easy.
For example:
class CommonPojo {}
class CustomerPojo extends CommonPojo {}
class PartialCustomerPojo extends CommonPojo {}
interface IResourceValid {
boolean isResourceValid(CommonPojo pojo);
}
class CustomerPojoValidator implements IResourceValid {
#Override
public boolean isResourceValid(CommonPojo pojo) {
//your validation for customer
return false;
}
}
class PartialCustomerPojoValidator implements IResourceValid {
#Override
public boolean isResourceValid(CommonPojo pojo) {
//your validation for partial customer
return true;
}
}
class CommonResource{
private DBDao dbDao;
private AnotherAPI api;
private IResourceValid validator;
public IResourceValid getValidator() {
return validator;
}
//constructor for DI
public Response Create(CommonPojo commonPojo) {
//logic to validate customerpojo
//logic to ensure user isn't a duplicate
//some other validation logic
//finally user creation/saving to DB
validator.isResourceValid(commonPojo);
return response.ok(200).build();
}
}
//#Path("/internal")
class CustomerResource{
private CommonResource resource;
//constructor for DI
public Response Create(CustomerPojo CustomerPojo) {
return resource.Create(CustomerPojo);
}
}
//#Path("/external")
class ApiResource{
private CommonResource resource;
//constructor for DI
public Response Create(PartialCustomerPojo partialCustomerPojo) {
return resource.Create(partialCustomerPojo);
}
}
DBDao dao = new DBDao();
AnotherAPI api = new AnotherAPI();
CommonResource castomerCreator = new CommonResource(new CustomerPojoValidator(), dao, api);
CommonResource apiCreator = new CommonResource(new PartialCustomerPojoValidator(), dao, api);
CustomerResource customerResource = new CustomerResource(castomerCreator);
ApiResource apiResource = new ApiResource(apiCreator);
customerResource.Create(somePojo);
apiResource.Create(someAnotherPojo);
There are many options and it all depends on what strategy you use. I prefer to use abstract class and make non abstract methods in it. When you extend the abstract class you choose which method you want to use.
In your scenario it should look something like this:
public abstract class AbstractResource {
private CustomerService customerService;
#Autowired
public void setCustomerService(CustomerService customerService) {
this.customerService = customerService;
}
public Response create(CustomerPojo customer) {
return customerService.createCustomerPojo(customer);
}
public Response create(PartialCustomerPojo customer) {
return customerService.createPartialCustomerPojo(customer);
}
}
The CustomerResource #Override only the method that needs:
#Path("/internal")
#Component
public class CustomerResource extends AbstractResource {
#POST
#Override
public Response create(PartialCustomerPojo customer) {
return super.create(customer);
}
}
Same for the ApiResource
#Path("/external")
#Component
public class ApiResource extends AbstractResource {
#POST
#Override
public Response create(CustomerPojo customer) {
return super.create(customer);
}
}
Everything goes in onle place - CustomerService, where you do your logic.
#Service
public class CustomerService {
#Autowired
private AnotherAPI api;
#Autowired
private DBDao dao;
public Response createCustomerPojo(CustomerPojo customer) {
//logic to validate customerpojo
//logic to ensure user isn't a duplicate
//some other validation logic
//finally user creation/saving to DB
}
public Response createPartialCustomerPojo(PartialCustomerPojo customer) {
//logic to validate PartialCustomerpojo
//supplement partialCustomerPojo
//logic to ensure user isn't a duplicate
//some other validation logic
//finally user creation/saving to DB
}
}
If you want to minimize the duplication you have to use an interface and implement in in each class:
public class CustomerPojo implements PojoInterface {
}
public class PartialCustomerPojo implements PojoInterface {
}
Now you can have only one abstract method:
public abstract class AbstractResource {
private CustomerService customerService;
#Autowired
public void setCustomerService(CustomerService customerService) {
this.customerService = customerService;
}
public abstract Response create(PojoInterface customer);
}
And then in 'the one place' you need to check each instance of the parameters:
public Response create(PojoInterface customer) {
if (customer instanceof CustomerPojo){
//logic to validate customerpojo
//logic to ensure user isn't a duplicate
//some other validation logic
//finally user creation/saving to DB
}else if (customer instanceof PartialCustomerPojo){
//logic to validate PartialCustomerpojo
//supplement partialCustomerPojo
//logic to ensure user isn't a duplicate
//some other validation logic
//finally user creation/saving to DB
}
}
Edit: Sorry for the long post...
This can be achieved by both of the following ways
Create an Interface and then implement on both of the target classes so they both can provide their local implementation
Use abstract class and then extend it.
Interface does not save you from coding but keeps things inline where abstract classes do not enforce anything so both have weaknesses. You can implement multiple interfaces but can only extend one class. Keeping that in mind I lean towards interfaces more
Since Java 8. Java supports default method using interface, which is from my opinion is the best way to go. You can provide default implementation in default method and user can override the method if they wish to. This will give you best of both Interface and Abstract class.
public interface CommonCode {
default public boolean create(CommonPojo commonPojo) {
//logic to validate customerPojo
//logic to ensure user isn't a duplicate
//some other validation logic
//finally user creation/saving to DB
Return response.ok(200).build();
}
}
#Path("/internal")
public class CustomerResource implements CommonCode {
private DBDao dbDao;
private AnotherAPI api;
//constructor for DI
create(CommonPojo)
}
#Path("/external")
public class ApiResource implements CommonCode {
private DBDao dbDao;
private AnotherAPI api;
//constructor for DI
create(CommonPojo)
}
Make an interface and have both classes implement it. Add an abstract base class call between the interface and the subclasses and refactor any common code into it.
Related
I have a Service class defined like this,
#RequiredArgsConstructor
class SomeService<T extends AbstractResponse> {
private final ValidationService<T> validationService;
....
}
And I have two kinds of AbstractResponse, ResponseA and ResponseB and have a validation service defined for both of them.
#Service("aValidationService");
class AValidationService<ResponseA> implements ValidationService<ResponseA> {
....
}
and
#Service("ValidationService");
class BValidationService<ResponseB> implements ValidationService<ResponseB> {
....
}
Right now spring is throwing an error because it's not able to deduce the implementation of ValidationService to use in SomeService as there are two implementations of it. How do I make spring deduce the correct implementation based on the type of AbstractResponse?
Hope that I understood your requirements.
You can not automatically inject, when you have (2) of the same kind. In this case ValidationService.
You could inject #ValidationServiceA, or #ValidationServiceB, or a List<ValidationServiceI> and then return the one you want based on a <T> type you care about:
The solution below highlights that.
The method getGenericParameter() is used to return the <T> parameter. This is to avoid the use of Reflection.
The method methodWhichDeterminesWhichServiceToUseBasedOnResponseType to used to determine which ValidationService to use based on the input that you require.
You can find the complete solution below, including a verification Test.
import org.springframework.stereotype.Service;
#Service
public class ValidationServiceA implements ValidationServiceI<ResponseA>{
#Override public Class<ResponseA> getGenericParameter() {
return ResponseA.class;
}
public void print(){
System.out.println("Service A");
}
}
#Service
public class ValidationServiceB implements ValidationServiceI<ResponseB>{
#Override public Class<ResponseB> getGenericParameter() {
return ResponseB.class;
}
public void print(){
System.out.println("Service B");
}
}
public interface ValidationServiceI<T>{
Class<T> getGenericParameter();
void print();
}
#Service
public class ServiceWhichCallsOthers {
#Autowired
private List<ValidationServiceI> validationServices;
public <T> ValidationServiceI<T> methodWhichDeterminesWhichServiceToUseBasedOnResponseType(T responseType){
Optional<ValidationServiceI> validationServiceSupportingResponse = validationServices.stream().filter(validationServiceI -> validationServiceI.getGenericParameter().equals(responseType)).findFirst();
return validationServiceSupportingResponse.get();
}
public void callValidationServiceA(){
methodWhichDeterminesWhichServiceToUseBasedOnResponseType(ResponseA.class).print();
}
public void callValidationServiceB(){
methodWhichDeterminesWhichServiceToUseBasedOnResponseType(ResponseB.class).print();
}
}
#SpringBootTest
public class ServiceWhichCallsOthersIT {
#Autowired
private ServiceWhichCallsOthers serviceWhichCallsOthers;
#Test
public void validateBasedOnResponseType(){
Assertions.assertEquals(ValidationServiceA.class, serviceWhichCallsOthers.methodWhichDeterminesWhichServiceToUseBasedOnResponseType(ResponseA.class).getClass());
Assertions.assertEquals(ValidationServiceB.class, serviceWhichCallsOthers.methodWhichDeterminesWhichServiceToUseBasedOnResponseType(ResponseB.class).getClass());
serviceWhichCallsOthers.callValidationServiceA();
serviceWhichCallsOthers.callValidationServiceB();
}
}
I'm creating telegram bot with Spring-Boot. I have AscractState class:
public abstract class AbstractState {
boolean isInputIndeed = Boolean.FALSE;
public abstract void handleInput(BotContext context);
//another parts
}
And there is extend which is
#Slf4j
public class AgeInputState extends AbstractState {
#Autowired
ClientService clientService;
public AgeInputState(boolean isInputIndeed) {
super(isInputIndeed, State.AGE_INPUT);
}
#Override
public void handleInput(BotContext context) {
context.getClient().setAge(Integer.parseInt(context.getInput()));
clientService.updateUser(context.getClient());
}
}
But i have touble with ClientService. Which annotations on class i need to add for autowiring this fiels?
Since this class has a constructor which only accepts a boolean, I assume you're needing to make lots of them.
Spring won't know you're wanting to load these as spring beans if you call this constructor directly. So creating these through a factory of some sort would be one way to go. Something like:
#Configuration
public class AgeInputStateFactory {
private #Autowired ClientService clientService;
#Bean
#Scope("prototype") // Makes a new one each time...
public AgeInputState create(final boolean isInputIndeed) {
return new AgeInputState(this.clientService, isInputIndeed);
}
}
Along with a newly designed AgeInputState constructor which also takes the ClientService field.
public class AgeInputState extends AbstractState {
private final ClientService clientService;
// Package private constructor so that no one outside
// of this package will call it. This means you can
// (try your best to) limit the construction to the
// factory class.
AgeInputState(final ClientService clientService,
final boolean isInputIndeed) {
super(isInputIndeed, State.AGE_INPUT);
this.clientService = clientService;
}
}
And then all you would do is wherever you need to create these AgeInputState Objects, you would #Autowire the AgeInputStateFactory instance, and call the create method whenever you need one.
I am a little confused. I tried to make a simple web app when user choose some type of client and operations performed in services will depend on this choice. I create interface that each of my client implements but how can I decide which implementation of client? If I will use if/else construction this will break open/closed principle(that is true?), cause when I would like to add new client i need to modify my code which adding new else. How can I do this correctly?
#RestController
public class SomeRest {
#Autowired
private SomeService someService;
#GetMapping("/test")
private Set<String> test(#RequestBody ClientType type) {
return someService.method(type);
}
}
#Service
public class SomeService {
private SomeInterface someInterface;
public Set<String> method(ClientType type) {
if (type.equals(ClientType.TYPE_ONE)) {
someInterface = new ClientOne();
return someInterface.operation();
} else if (type.equals(ClientType.TYPE_TWO)) {
someInterface = new ClientTwo();
return someInterface.operation();
}
return null;
}
}
I am not sure of using inheritance / interface implementation in particular situation.
In my simple Spring MVC application I have #Entity class TennisPlayer, which is inherited from abstract class Player (TennisPlayer adds some attributes).
Also I have class TennisPlayerForm, which is inherited from abstract class PlayerForm (TennisPlayerForm adds some attributes again).
User fills the form about tennis player in .jsp page and TennisPlayerForm object is used to represent filled values and then on the basis of this object is created TennisPlayer object and saved into database.
Creation of TennisPlayer object is responsibility of class TennisPlayerDbService. This class is implementation of interface PlayerService.
I have following #Controller, which handles requests:
#Controller
public class NewPlayerController {
#Resource(name="tennisPlayerService")
private PlayerService playerService;
//omitted RequestMethod.GET handler method
#RequestMapping(value = "/newplayer", method = RequestMethod.POST)
public String newplayer(Locale locale, #ModelAttribute("tennisPlayerForm") #Valid TennisPlayerForm tennisPlayerForm,
BindingResult result, RedirectAttributes redirectAttributes) {
playerService.createPlayer(tennisPlayerForm);
return "redirect:/allplayers";
}
}
Part of my source code looks like this:
public interface PlayerService {
public void createPlayer(PlayerForm playerForm);
}
#Service(value="tennisPlayerService")
public class TennisPlayerDbService implements PlayerService {
private TennisPlayerDAO dao;
#Autowired
public void setDao(TennisPlayerDAO dao) {
this.dao = dao;
}
#Override
public void createPlayer(PlayerForm playerForm) {
TennisPlayerForm tennisPlayerForm = null;
if (playerForm instanceof TennisPlayerForm) {
tennisPlayerForm = (TennisPlayerForm) playerForm;
}
else {
throw new IllegalArgumentException("Must be of type TennisPlayerForm.");
}
TennisPlayer player = new TennisPlayer();
player.setName(tennisPlayerForm.getName());
player.setSurname(tennisPlayerForm.getSurname());
player.setAge(tennisPlayerForm.getAge());
player.setRacket(tennisPlayerForm.getRacket());
player.setRanking(tennisPlayerForm.getRanking());
player.setSponsor(tennisPlayerForm.getSponsor());
player.setCoach(tennisPlayerForm.getCoach());
player.setClub(tennisPlayerForm.getClub());
dao.saveAndFlush(player);
}
}
Is it justified to use inheritance and interface implementations like this in this situation, when concrete implementation of PlayerService (TennisPlayerDbService) expects instance of particular class, although these potential classes have common parent?
Finally I solved my problem according to your comments and answers.
I deleted PlayerForm abstract class, TennisPlayerForm and mixed javax.validation and javax.persistence annotations in #Entity classes Player and Tennis Player.
Previously mentioned code now looks like this:
#Controller
public class NewPlayerController {
#Resource(name="tennisPlayerService")
private PlayerService<TennisPlayer> playerService;
//omitted RequestMethod.GET handler method
#RequestMapping(value = "/newplayer", method = RequestMethod.POST)
public String newplayer(Locale locale, #ModelAttribute("tennisPlayer") #Valid TennisPlayer tennisPlayer,
BindingResult result, RedirectAttributes redirectAttributes) {
if(result.hasErrors()) {
return "newplayer";
}
playerService.createPlayer(tennisPlayer);
MessageUtil.flash(locale, redirectAttributes, "success", "signup.success");
return "redirect:/allplayers";
}
}
public interface PlayerService<T extends Player> {
public void createPlayer(T player);
public List<T> getAllPlayers();
}
#Service(value="tennisPlayerService")
public class TennisPlayerDbService implements PlayerService<TennisPlayer> {
private TennisPlayerDAO dao;
#Autowired
public void setDao(TennisPlayerDAO dao) {
this.dao = dao;
}
#Override
public void createPlayer(TennisPlayer player) {
dao.saveAndFlush(player);
}
#Override
public List<TennisPlayer> getAllPlayers() {
return dao.findAll();
}
}
Normally your service does not need to know you are working with a form. Your form is purely created to be the model in the model-view-controller architecture of your webpage. (your jsp being the view and your controller being the c-part)
Are you also planning on using other types of players than a TennisPlayer? If not it all seems like premature optimisation and you should keep it as simple as possible.
#Component
#Qualifier("SUCCESS")
public class RandomServiceSuccess implements RandomService{
public String doStuff(){
return "success";
}
}
#Component
#Qualifier("ERROR")
public class RandomServiceError implements RandomService{
public String doStuff(){
throw new Exception();
}
}
the calling code
#Controller
public class RandomConroller {
#Autowired
private RandomService service;
public String do(){
service.doStuff();
}
}
What I need to do here is to have them swapped based on a value can be retrieved from some custom http header from a http request. Thank you!
I'm totally agree with Sotirios Delimanolis that you need to inject all the implementations and choose one of them at runtime.
If you have many implementations of RandomService and don't want to clutter RandomController with selection logic, then you can make RandomService implementations responsible for selection, as follows:
public interface RandomService{
public boolean supports(String headerValue);
public String doStuff();
}
#Controller
public class RandomConroller {
#Autowired List<RandomService> services;
public String do(#RequestHeader("someHeader") String headerValue){
for (RandomService service: services) {
if (service.supports(headerValue)) {
return service.doStuff();
}
}
throw new IllegalArgumentException("No suitable implementation");
}
}
If you want to define priorities for different implementations, you may use Ordered and put the injected implementations into a TreeSet with OrderComparator.
Qualifier should be used to specify which instance of the interface you want injected in the field after specifying different IDs for each one. Following #Soritios' advice you could do something like:
#Component("SUCCESS")
public class RandomServiceSuccess implements RandomService{
public String doStuff(){
return "success";
}
}
#Component("ERROR")
public class RandomServiceError implements RandomService{
public String doStuff(){
throw new Exception();
}
}
#Component
public class MyBean{
#Autowired
#Qualifier("SUCCESS")
private RandomService successService;
#Autowired
#Qualifier("ERROR")
private RandomService successService;
....
if(...)
}
...or you could obtain just the instance you want from the application context based on your parameter:
#Controller
public class RandomConroller {
#Autowired
private ApplicationContext applicationContext;
public String do(){
String myService = decideWhatSericeToInvokeBasedOnHttpParameter();
// at this point myService should be either "ERROR" or "SUCCESS"
RandomService myService = applicationContext.getBean(myService);
service.doStuff();
}
}
You can just inject both and use the one you need.
#Inject
private RandomServiceSuccess success;
#Inject
private RandomServiceError error;
...
String value = request.getHeader("some header");
if (value == null || !value.equals("expected")) {
error.doStuff();
} else {
success.doStuff();
}