I have this question about best practices in following examples:
interface Request;
interface Service {
void process(Request request)
}
class MyService implements Service;
class YourService implements Service;
class MyRequest implements Request;
class YourRequest implements Request;
But how to ensure that MyService will always receive MyRequest and YourService will get YourRequest only, and not in the opposite way? Obvious answer "if-instance-of-check" in MyService.process(...) seems ugly and somehow against SOLID principles. Maybe there are better ways around?
Maybe generics would be good solution? (But then, how to use them in code that has to run under Java 1.4?)
Put simply, you are establishing an interface that you then don't want to adhere to, so it's not really an ideal design.
What I mean is, if MyService implements Service, then it must be able to take any kind of request. Otherwise it isn't following the defined contract.
I would question why you have the Service interface at all in this instance, and if you do need it (for other methods) whether it's appropriate for the process(Request request) method to be on there if subclasses are not going to honour it.
If the design of the contract is that each Service can process any kind of Request, then your implementation of MyService , which only takes MyRequest (and breaks if other kinds of Requests are passed in), is wrong.
If the design of the contract is that Service and Request subclasses maps to each other, e.g., MyService can (and should) only process a MyRequest, then you will need to change the interface of Service. Otherwise, the current interface as written in the question does not do what the question describes it to do. One way to fix is to parameterize the Service interface:
interface Service<R> {
void process(R request);
}
then your concrete MyService will be
public class MyService implements Service<MyRequest> {
public void process (MyRequest r) {/*blah*/}
}
You can see an example of this in action in the JDK - the Comparator interface does exactly this, for exactly the same reason. http://java.sun.com/javase/6/docs/api/java/util/Comparator.html
I cant see why you would, but if you still want to restrict the hierachy of MyRequest to be a request, then you can swap Service<R> with Service<R extends Request>
edit: this obviously doesnt run in 1.4, so to do the same thing[1] , you will need to use a visitor pattern. Its uglier, but 1.4 is ugly =)
interface Service {
void process(Request visitor);
}
interface RequestVisitor {
void visitMyRequest(MyService service);
void visitYourRequest(YourService service);
void visitTheOtherRequest(TheOtherService service);
}
interface Request extends RequestVisitor { /* and any extra methods required for request*/ }
public class MyService implements Service {
public process(Request r) {r.visitMyRequest(this);}
public void doSpecialMyProcessing(MyRequest request) { /* your code using MyRequest*/ }
}
public class YourService implements Service {
public process(Request r) {r.visitYourRequest(this);}
public void doSpecialYourProcessing(YourRequest request) { /* your code using YourRequest */ }
}
public class MyRequest implements Request {
void visitMyRequest(MyService service) {
service.doSpecialMyProcessing(this);
}
void visitYourRequest(YourService service) {
throw new UnsupportedOperation("Cannot call visitYourRequest in MyRequest!");
}
void visitTheOtherRequest(TheOtherService service) {
throw new UnsupportedOperation("Cannot call visitTheOtherRequest in MyRequest!");
}
}
public class YourRequest implements Request {
void visitMyRequest(MyService service) {
throw new UnsupportedOperation("Cannot call visitMyRequest in YourRequest !");
}
void visitYourRequest(YourService service) {
service. doSpecialYourProcessing(this);
}
void visitTheOtherRequest(TheOtherService service) {
throw new UnsupportedOperation("Cannot call visitTheOtherRequest in YourRequest !");
}
}
[1] actually its not the same, because now you will need to write a method for each request subtype. In 1.4, you would have to cast and do instanceof etc, to achieve what 1.5 can do with generics.
In my opinion generics would suit better here. Your interfaces pretend that a service can handle any type of Request. But in fact the implementations of each seem to be tightly coupled.
Anything implementing Service should expect to implements its methods as they are. If MyService and YourService require different method prototypes, then they are different interfaces.
Think of it from the other direction. Without knowing the implementation behind a Service interface, any caller should able to call Service.process(request) with any implementation of Request, and expect to receive a valid response.
try introducing another level of indirection:
interface Module {
Service createService();
Request createRequest();
}
class MyModule implements Module {
Service createService() { return new MyService(); }
Request createRequest() { return new MyRequest(); }
}
class YourModule implements Module {
Service createService() { return new YourService(); }
Request createRequest() { return new YourRequest(); }
}
Related
Ok so I couldn't find any helpful materials on this topic, a big chunk of articles I found had one method that was annotated with #HystrixCommand and had defined a fallback method.
The other solution I found was using #DefaultProperties(defaultFallback = "fallbackMethod") but the problem with this is that the methods need to have compatible return types.
Unfortunately for me in my service I have many methods with completely different signatures and also I need to get hold of the throwable (in docs it is mentioned that you cannot have any parameters for a default fallback method). The methods look something like this:
#Service
#RequiredArgsConstructor
public class MyService {
private final FeignClient feignClient;
#Override
public String methodA(final CustomObjectA o, final String entity) {
...
}
#Override
public String methodB(final String collection, final Map<String, Object> requestBody) {
...
}
#Override
public String methodC(final String collection, final String id, final Map<String, Object> requestBody) {
...
}
}
And ofc I have more than 3 methods def in the service...
The thing I really want to avoid is making 20 hystrix default fallback methods.
Is there a way where I could def a standard fallback for all methods, no matter what the signatures they have, or am I stuck with defining a fallback method for every single method?
Thanks in advance!!
You will have to implement a fall back for each method.
However using the FallbackFactory might make this easier and allow each method to call one reusable method.
Maybe you don't really want hystrix fallbacks if they are the same for each method. All try catch might solve the same problem.
Let me share the code snippet used in my project.
To call an api like http://www.baidu.com/xxx, you have below steps to follow.
1.Api Definition (fallback = WebServiceApiFallback.class)
#Component
#FeignClient(value = "webServiceApi", configuration = FeignConfiguration.class, fallback = WebServiceApiFallback.class)
public interface WebServiceApi {
#Headers(value = {"Content-Type: application/json", "Accept-Encoding: gzip,deflate"})
#GetMapping(value = "/xxx")
BaseResponse<YourResponse> xxx(YourRequest request);
2.Fallback Definition
#Component
public class WebServiceApiFallback implements WebServiceApi {
#Override
public BaseResponse<YourResponse> xxx(YourRequest request) {
// Your Fallback Code here, when api request failed.
}
3.api host configuration, maybe application.properties...
webServiceApi.ribbon.listOfServers=http://www.baidu.com
4.use it
#Autowired
private WebServiceApi webServiceApi;
For any api, you can just define you request and response, and feign will do the request、 encode、and decode.
[Ref] https://github.com/spring-cloud/spring-cloud-netflix/issues/762
I have an interface:
public interface ThirdPartySystemCaller {
void sendRequest(String request) throws ThirdPartySystemException;
}
And implementation:
#Slf4j
#Service
public class ThirdPartySystemCallerImpl implements ThirdPartySystemCaller {
#Override
public void sendRequest(String request) throws ThirdPartySystemException {
if (request == null) throw new ThirdPartySystemException();
log.info("send: {}", request);
}
}
And I have a CryptoService witch can sign request:
public interface CryptoService {
String signRequest(String request) throws CryptoException;
}
And It implementation:
#Slf4j
#Service
public class CryptoServiceImpl implements CryptoService {
#Override
public String signRequest(String request) throws CryptoException {
if (request.length() > 100) throw new CryptoException(); //just for example
return "signed " + request;
}
}
Now, I can use these services:
String signedRequest = cryptoService.signRequest("Hello");
thirdPartySystemCaller.sendRequest(signedRequest);
But I need to call both services each time. I want to create Proxy:
#Slf4j
#Service
public class ThirdPartySystemCallerSignedProxy implements ThirdPartySystemCaller {
private final ThirdPartySystemCaller thirdPartySystemCaller;
private final CryptoService cryptoService;
public ThirdPartySystemCallerSignedProxy(ThirdPartySystemCaller thirdPartySystemCaller, CryptoService cryptoService) {
this.thirdPartySystemCaller = thirdPartySystemCaller;
this.cryptoService = cryptoService;
}
#Override
public void sendRequest(String request) throws ThirdPartySystemException {
String signedRequest = cryptoService.signRequest(request);
thirdPartySystemCaller.sendRequest(signedRequest);
}
}
But my ThirdPartySystemCallerSignedProxy implement ThirdPartySystemCaller interface and sendRequest method throw only ThirdPartySystemException. But if cryptoService throw CryptoException I need throw it too.
How can I do it?
I was thinking to make unchecked exceptions, But I need to be checked.
Create base exception
You can create abstract exception BusinessException which can be a base exception for ThirdPartySystemException and CryptoException. Now, you can define that sendRequest method throws BusinessException and real exception depends from given problem.
Facade
ThirdPartySystemCallerSignedProxy is a bad name because it reminds Proxy pattern which is not what you have implemented. This class reminds Facade pattern because you want to create unified interface with simpler API for two different interfaces. In that case you can wrap CryptoException if it will be thrown into ThirdPartySystemException or also create base exception and declare it in method. It is even better because you do not know which kind of exception will be thrown but for sure it will be BusinessException.
Chain of Responsibility
Many libraries use Chain of Responsibility to handle request -> response communication. All chain cells need to implement the same interface with base exception in declaration if needed. You can build the chain in bean definition. It is a little bit easier to maintain because all cells are independent and does not have to know about each other as in Facade. You can build chain in #Bean method declaration like below:
#Bean
public ServiceChainCell thirdPartyCaller() {
CryptoService crypto = cryptoService();
ThirdPartySystemCaller caller = thirdPartySystemCaller();
// Create chain
crypto.setNext(caller);
return crypto;
}
setNext method comes from ServiceChainCell interface which also should have sendRequest(String request) method.
Read more about these patterns and you will find the best solution for you.
I have a proxy service which exposes several APIs - each requesting an Object of a specific type and returning an Object of a specific type. Requests come to my ProxyService which are mapped to the format expected by the underlying service:
public class ProxyService {
public ProxyServiceResponse_A performA(ProxyServiceRequest_A request);
public ProxyServiceResponse_B performB(ProxyServiceRequest_B request);
public ProxyServiceResponse_C performC(ProxyServiceRequest_C request);
...
}
public class ProxiedService {
public ProxiedServiceResponse_A performA(ProxiedServiceRequest_A request);
public ProxiedServiceResponse_B performB(ProxiedServiceRequest_B request);
public ProxiedServiceResponse_C performC(ProxiedServiceRequest_C request);
...
}
I want to create generic mappers for mapping incoming ProxyService requests to ProxiedService requests:
public class MyRequestMapper {
public ProxiedServiceRequest_A mapRequestA(ProxyServiceRequest_A request);
...
}
I know of dozer and apache-velocity but I don't want to use those, instead do this on my own. Is there a design pattern or a generic way to achieve this?
You might consider a generic interface.
interface RequestMapper<T, U> {
U mapRequest(T request);
}
class ARequestMapper implements RequestMapper<ProxyServiceRequest_A, ProxiedServiceRequest_A> {
#Override
public ProxiedServiceRequest_A mapRequest(ProxyServiceRequest_A request) {
//TODO
}
}
class BRequestMapper implements RequestMapper<ProxyServiceRequest_B, ProxiedServiceRequest_B> {
#Override
public ProxiedServiceRequest_B mapRequest(ProxyServiceRequest_B request) {
//TODO
}
}
I have gone through couple of tutorials, where I could see that an Interface which JAX-RS annotation is created. And later an implementation of the same is done.
Why is so? Can't I expose a concrete class directly as a RESTful Service? Is that a bad practice? Below is one of the samples which I came across in this question.
public interface ICRUD {
#POST
#Consumes("application/json")
#Produces("application/json")
#Path("create")
public String createREST(String transferObject);
#GET
#Consumes("application/json")
#Produces("application/json")
#Path("retreive/{id}")
public String retreiveREST(#PathParam("id") String id);
#POST
#Consumes("application/json")
#Produces("application/json")
#Path("update")
public void updateREST(#Suspended final AsyncResponse asyncResponse,
final String transferObject) ;
#DELETE
#Consumes("application/json")
#Produces("application/json")
#Path("delete/{id}")
public String deleteREST(#PathParam("id") String id);
}
Can't I expose a concrete class directly as a RESTful Service?
You definitely can. Have you tried it? It should work just fine.
Is that a bad practice?
Personally (and this is just my preference), I think it's bad practice to use interfaces. Some people may argue that it cleans up your code, but there are problems that come with using interfaces, for instance annotation inheritance can sometimes cause a problem for those who don't understand what the problem is. It can be really hard to spot.
If your argument is that interfaces make code cleaner, I have a couple arguments.
(1) Your code is less understandable. You need to keep referring back to the interface to see what arguments are for (e.g. inspecting the method parameter annotations). It's easier when all the annotations are in the code your actually writing.
(2) Interfaces have no implementation, so you would still need to implement every class. I personally go with an abstract base class that will implement all the basic operations. For example
public abstract class AbstractResource<T extends BaseEntity> {
private final Repository<T> repository;
public AbstractResource(Repository<T> repository) {
this.repository = repository;
}
#GET
public List<T> getAll() {
return this.repository.findAll();
}
#GET
#Path("{id}")
public T getOne(#PathParam("id") long id) {
T result = this.repository.findOne(id);
if (result == null) {
throw new NotFoundException();
}
return result;
}
#POST
public Response create(T entity, #Context UriInfo uriInfo) {
T saved = this.repository.save(entity);
// BaseEntity should have an id property
long id = saved.getId();
URI createdUri = uriInfo.getAbsoluteUriBuilder()
.path(id).build();
return Response.created(createdUri).build();
}
}
You could do the same for #PUT and #DELET. The core functionality is the same for all resource collections. The only thing that would need to change is the Repository type. All your implementations could just extend it like
#Path("pets")
public class PetsResource extends AbstractResource<Pet> {
#Inject
public PetsResource(PetsRepository repository) {
super(repository);
}
}
This is much cleaner. You don't need to implement the same basic CRUD operations for your concrete resources. If you want to provide other resource methods in your concrete resource class, you can do so.
To say in short - the interface is not mandatory. You can expose a class as a service.
Here's a great discussion about this
https://softwareengineering.stackexchange.com/questions/150045/what-is-the-point-of-having-every-service-class-have-an-interface
In my endpoint, I have some methods with #GET and some methods with #POST. #GETs are working fine, but #POSTs always return 404.
Here is some part from the endpoint's interface:
public interface TestEndpoint {
#GET
#Path("/ping")
Response ping();
#POST
#Path("/weather/{iata}/{pointType}")
Response updateWeather(#PathParam("iata") String iataCode,
#PathParam("pointType") String pointType,
String datapointJson);
#POST
#Path("/airport/{iata}/{lat}/{long}")
Response addAirport(#PathParam("iata") String iata,
#PathParam("lat") String latString,
#PathParam("long") String longString);
#GET
#Path("/exit")
Response exit();
}
Here is the server initialization part:
public class TestServer {
private static final String BASE_URL = "http://localhost:9090/";
public static void main(String[] args) {
try {
final ResourceConfig resourceConfig = new ResourceConfig();
resourceConfig.register(TestEndpointImpl.class);
HttpServer server = GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URL), resourceConfig, false);
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
server.shutdownNow();
}));
HttpServerProbe probe = new HttpServerProbe.Adapter() {
public void onRequestReceiveEvent(HttpServerFilter filter, Connection connection, Request request) {
System.out.println(request.getRequestURI());
}
};
server.getServerConfiguration().getMonitoringConfig().getWebServerConfig().addProbes(probe);
server.start();
Thread.currentThread().join();
server.shutdown();
} catch (IOException | InterruptedException ex) {
Logger.getLogger(TestServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
where, TestEndpointImpl is an implementation of TestEndpoint (as the name implies) with class-level annotation #Path("/collect").
When I perform GET requests, it works fine. But POSTs are problematic. Corresponding methods are not called.
As a side note, probe prints both GET and POST requests as expected, so I am sure that requests reach the server and paths are ok.
Is there any suggestion?
EDIT: Some snippet from the implementation:
#Path("/collect")
public class TestEndpointImpl implements TestEndpoint {
...
#Override
public Response updateWeather(#PathParam("iata") String iataCode, #PathParam("pointType") String pointType,
String datapointJson) {
System.out.println("TRACE: " + datapointJson);
// do something and return a Response
}
...
}
The registered probe prints /collect/weather/BOS/wind, but updateWeather is not called.
Short answer
Copy the #POST and the #Path annotations to the method implementation. It will do the trick.
Long answer
The section regarding annotation inheritance of the JAX-RS 2.0 specification (the specification which Jersey is the reference implementation) is pretty clear. See the quote below:
3.6 Annotation Inheritance
JAX-RS annotations may be used on the methods and method parameters of a super-class or an implemented interface. Such annotations are inherited by a corresponding sub-class or implementation class method provided that the method and its parameters do not have any JAX-RS annotations of their own. Annotations on a super-class take precedence over those on an implemented interface. The precedence over conflicting annotations defined in multiple implemented interfaces is implementation specific. Note that inheritance of class or interface annotations is not supported.
If a subclass or implementation method has any JAX-RS annotations then all of the annotations on the superclass or interface method are ignored. E.g.:
public interface ReadOnlyAtomFeed {
#GET
#Produces("application/atom+xml")
Feed getFeed();
}
#Path("feed")
public class ActivityLog implements ReadOnlyAtomFeed {
public Feed getFeed() {...}
}
In the above, ActivityLog.getFeed inherits the #GET and #Produces annotations from the interface. Conversely:
#Path("feed")
public class ActivityLog implements ReadOnlyAtomFeed {
#Produces("application/atom+xml")
public Feed getFeed() {...}
}
In the above, the #GET annotation on ReadOnlyAtomFeed.getFeed is not inherited by ActivityLog.getFeed and it would require its own request method designator since it redefines the #Produces annotation.
For consistency with other Java EE specifications, it is recommended to always repeat annotations instead of relying on annotation inheritance.
That can also happen if the url is not in the correct format; for example you could have sent a request without the correct path parameters.