So I have the following structure:
public abstract class Processor<T extends BaseContainer> {
protected abstract T initializeContainer(String requestID, Map<String, String> details);
protected abstract boolean validateContainer(T request);
protected abstract void process(T request);
public final process(String requestID, Map<String, String> details) {
T request = initializeContainer(requestID, details);
if (!validateContainer(request)) {
process(request);
}
}
}
public abstract class BaseContainer() {
protected final String requestID;
protected BaseContainer(String requestID, Map<String, String> details) {
this.requestID = requestID;
// set some other fields using details
}
}
Everytime I need to add a new Processor (with a corresponding new Container), I will need to:
public class SampleProcessor extends Processor<SampleContainer> {
#Override
protected SampleContainer initializeContainer(String requestID, Map<String, String> details) {
return new SampleContainer(requestID, details);
}
}
// SampleContainer can contain other details, but omitted for clarity
public class SampleContainer extends BaseContainer {
public SampleContainer(String requestID, Map<String, String> details) {
super(requestID, details);
}
}
I don't like the fact that I need to override initializeContainer for every Processor I add, especially when I don't change the constructor's parameters of Container (it will be always String requestID, Map<String, String> details
I understand that I can't simple call new T(requestID, details) in Processor. And I would imagine I will need some sort of factory (?) if I want to implement initializeContainer at base class.
Can you help to suggest anyway I can achieve this? Thank you.
Edit 1: I added two more methods to provide better context Processor
Everythings fine
This is a pattern called the abstract-factory.
Everytime I need to add a new Processor (with a corresponding new Container), I will need to:
This is the main intend of the pattern (ebenda)
the client (you) software creates a concrete implementation (your SampleProcessor) of the abstract factory (Processor) and then uses the generic interface of the factory to create (via initializeContainer) the concrete objects (your SampleContainer)...
I'd refactor the method name to createContainer, because that's what you do with your implementation - you don't setup an existing one but the make a new one.
Your simple example only calls the container constructor. But the 'processor creation and initialization' process could vary. Maybe, some processors for some container need special treatment. Then the implementations of the method would look different for each container subclass again.
An alternative common pattern, to solve this common problem, would be adding another abstract method like
public abstract Class<T> getProcessorType();
and implement it like this on every container implementation:
#Override
public Class<MyProcessor> getProcessorType() {
return MyProcessor.class;
}
The base class then could implement the create method for processors:
public T createProcessor(String requestID, Map<String, String> details) {
T processor;
try {
processor = getProcessorType().newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace(); // or handle correctly
}
processor.init(requestId, details)
return processor;
}
(Note that this requires a no-args processor constructor)
Related
As far as I can see, Jersey does not support deep-object parameters (parameters in the form of ?type[n1]=v1&type[n2]=v2).
Is it possible to add this as extension? And if so, how?
My idea is to have an annotation similar to #QueryParam, let's say #DeepObjectParam, and I would use it to annotate a field like this:
#GET
public Response(#DeepObjectParam("type") Map<String, String> type) {
// ...
}
And have Jersey inject the map.
Depending on the version of Jersey you are using, the interface that you need to implement will be different. In Jersey 2.0-2.25.1, the class is ValueFactoryProvider and 2.26+ it's ValueParamProvider.
With both classes, the implementation will be similar. There is one method to implement which takes a Parameter argument. We use this Parameter to check whether this provider is able to handle this type of parameter. If the check passes, then the method should return either a Factory or a Function (depending on the version) that provides the actual argument. If the check fails, it should return null.
For example, if the parameter is annotated with #DeepObjectParam and the parameter type is Map, then we should check for these two things.
#Override
public Function<ContainerRequest, ?> getValueProvider(Parameter param) {
if (param.isAnnotationPresent(DeepObjectParam.class) && isStringStringMap(param)) {
return new DeepParamFunction(param);
}
return null;
}
Here, the DeepParamFunction is a Function that takes a single ContainerRequest argument. It will do the parsing of the query parameter and then return the Map.
After you've implemented the required class, you need to register it with Jersey. Again, depending on which version of Jersey you are using, the registration will be different (but similar). In both cases you need to register an AbstractBinder with the ResourceConfig
register(new AbstractBinder() {
#Override
protected void configure() {
bind(DeepObjectParamProvider.class)
// 2.0-2.25.1 you will use ValueFactoryProvider.class
.to(ValueParamProvider.class)
.in(Singleton.class);
}
});
For both versions of Jersey, you will use the same AbstractBinder class, but the imports will be different. In 2.0-2.25.1, you will look for hk2 in the package name. In 2.26, you will look for jersey in the package name. The other difference is in the to() method. In 2.0-2.25.1 you will use ValueFactoryProvider and 2.26+, you will use ValueParamProvider.
Here is an example implementation of the ValueParamProvider (for Jersey 2.26+). The implementation for ValueFactoryProvider will be very similar
public class DeepObjectParamProvider implements ValueParamProvider {
#Override
public Function<ContainerRequest, ?> getValueProvider(Parameter param) {
if (param.isAnnotationPresent(DeepObjectParam.class) && isStringStringMap(param)) {
return new DeepParamFunction(param);
}
return null;
}
private static boolean isStringStringMap(Parameter param) {
if (!param.getRawType().equals(Map.class)) {
return false;
}
ParameterizedType type = (ParameterizedType) param.getType();
Type[] genericTypes = type.getActualTypeArguments();
return genericTypes[0].equals(String.class) && genericTypes[1].equals(String.class);
}
#Override
public PriorityType getPriority() {
// Use HIGH otherwise it might not be used
return Priority.HIGH;
}
private static class DeepParamFunction implements Function<ContainerRequest, Map<String, String>> {
private final Parameter param;
private DeepParamFunction(Parameter param) {
this.param = param;
}
#Override
public Map<String, String> apply(ContainerRequest request) {
Map<String, String> map = new HashMap<>();
DeepObjectParam anno = param.getAnnotation(DeepObjectParam.class);
String paramName = anno.value();
MultivaluedMap<String, String> params = request.getUriInfo().getQueryParameters();
params.forEach((key, list) -> {
// do parsing of params
});
return map;
}
}
}
For a complete running (2.26+) example, take a look at this post. For versions earlier than 2.26, I've refactored that example and posted it to this Gist.
P.S.
While implementing the provider and debugging, don't be surprised when the method is called more than once. What happens is that on startup, Jersey will validate all the resource methods and make sure that all the parameters are able to be processed. How Jersey does this is by passing each Parameter to all the providers until one is reached that doesn't return null. So the more resource methods you have, the more times your provider will be called. See this post for more elaboration.
After a few years of coding in python, I recently moved to Java for a project.
While working with Python, I had a pretty implementation for a factory.
# file abstract_product.py
from abc import ABC, abstractmethod
class AbstractProduct(ABC):
#abstractmethod
def do_something():
pass
# file product_factory.py
from abstract_product import AbstractProduct
class ProductFactory:
def __init__(self):
self._creators = {}
def get(self, product_name) -> Product:
if product_name not in self._creators:
raise ValueError('No valid implementation !')
return self._creators[product_name]()
def register(self, product_name, product):
self._creators[product_name] = product
product_factory = ProductFactory()
# file product1.py
from abstract_product import AbstractProduct
from product_factory import product_factory
class Product1(AbstractProduct):
def do_something():
# does something
pass
product_factory.register('product1', Product1)
Now the advantage would be, that if I had a new Implementation for
Product, all I had to do was
# file product2.py
from abstract_product import AbstractProduct
from product_factory import product_factory
class Product2(AbstractProduct):
def do_something():
# does something
pass
product_factory.register('product2', Product2)
The advantages of the above approach were:
I had my factory as a singleton. Defining the variable in module ensured that.
Registering a new Product, included no changes to the existing code.
No dirty if else ladder has to be set up any where!
The new implementation registered to the factory in their own module. SO CLEAN :D :D
All the client code needed to know was the product_factory from above and the string parameter based on which the client would get some implementation of Product.
However, now with Java, I am thinking what can I do, to get close to the simplicity and extensibility that the above approach had !
Note:
Please also suggest some other approach that you might have come across for an extensible factory that might even be better than the above !
Your python code can be quite easily translated to Java, and it doesn't look too "foreign".
// could even be an interface
abstract class Product {
// ...
abstract void doSomething();
}
final class ProductFactory {
// not strictly a singleton, to allow you to create multiple factories
// your python code allows this too
private static ProductFactory instance = new ProductFactory();
public static ProductFactory getInstance() {
return instance;
}
private HashMap<String, Supplier<? extends Product>> creators = new HashMap<>();
public void register(String productName, Supplier<? extends Product> creator) {
creators.put(productName, creator);
}
public Product get(String productName) {
Supplier<? extends Product> creator = creators.get(productName);
if (creator == null) {
throw new IllegalArgumentException("No valid implementation !");
}
return creator.get();
}
}
class Product1 extends Product {
#Override
void doSomething() {
}
}
Example of registering and getting a product:
ProductFactory.getInstance().register("product1", Product1::new);
System.out.println(ProductFactory.getInstance().get("product1"));
This is how I like to do it (taken another class example),
public class MyFactory {
private Map<String, MyInterface> factoryMap = new HashMap<>();
#Autowired
public MyFactory(List<MyInterface> listOfObjectsImplementingMyInterface) {
for (MyInterface myInterface : listOfObjectsImplementingMyInterface) {
//Get the class annotation value, use it as map's key
String strategyKey = myInterface.getClass().getAnnotationsByType(Component.class)[0].value();
factoryMap.put(strategy, myInterface);
}
}
// To get an instantiation from factory
public MyInterface getFromFactory(String strategyKey) {
return factoryMap.get(strategyKey);
}
}
The above example is a snippet from a spring f/w project, and with this method you can utilise the spring annotations to populate the factory rather than using messy if/else/switch blocks. The above method can be extended to other cases as well with custom annotations.
In my opinion, a strict conversion from your Python code into Java would be the snippet from below. Show this should feel more familiar to you.
For a simple application, you could make your Factory use static or use the Singleton design pattern to ensure a single instance.
If you are using some frameworks, is quite likely that it offers an alternative that requires less coding though and better testability.
import java.util.HashMap;
import java.util.Map;
// AbstractProduct may better be an 'interface' even
abstract class AbstractProduct {
abstract void doSomething();
}
class Product1 extends AbstractProduct {
#Override
void doSomething() {
System.out.println("I'm Product ONE (1)");
}
}
class Product2 extends AbstractProduct {
#Override
void doSomething() {
System.out.println("I'm Product TWO (2)");
}
}
class ProductFactory {
private final Map<String, Class<? extends AbstractProduct>> creators;
ProductFactory() {
this.creators = new HashMap<>();
}
AbstractProduct get(String productName) {
if (!creators.containsKey(productName)) {
throw new RuntimeException("No valid implementation !");// <-- better define or use a specific exception
}
try {
return creators.get(productName).newInstance(); // <-- Class.newInstance is deprecated since Java9, check docs for replacement
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e); // <-- deal with it properly
}
}
void register(String productName, Class<? extends AbstractProduct> productClass) {
creators.put(productName, productClass);
}
}
public class PythonFactoryThing {
public static void main(String[] args) {
ProductFactory productFactory = new ProductFactory();
productFactory.register("product1", Product1.class);
productFactory.register("product2", Product2.class);
productFactory.get("product1").doSomething();
productFactory.get("product2").doSomething();
productFactory.get("product3").doSomething(); // <-- throws exception
}
}
EDIT: if you don't want a separate place/file to register, you could use a static initialisation block (some Database drivers do that).
You'd have to adapt the above code like this:
Make a singleton out of your Factory:
private ProductFactory() {}// private constructor so nobody else cana instantiate it
public static final ProductFactory INSTANCE = new ProductFactory();
And make each class do something like this:
class Product2 extends AbstractProduct {
static {
ProductFactory.INSTANCE.register("product2", Product2.class);
}
#Override
void doSomething() {
System.out.println("I'm Product TWO (2)");
}
}
But for that to work you would also need to explicitly load the classes you want to have registered. Either by using them some place before using the Factory, or by calling:
Class.forName("Product1");
Since the class loader only loads the classes that are explicitly needed. Which I suppose would be equivalent in Python to importing the file in your script.
Let's say I have an application that is responsible for taking a vendor message and converting into a canonical message. For example:
public class MessageA extends VendorMessage { ... }
public class MessageB extends VendorMessage { ... }
public class MessageX extends CanonicalMessage { ... }
public class MessageY extends CanonicalMessage { ... }
Where MessageA maps to MessageX and MessageB maps to MessageY.
My approach is that I have one transformer class per message type to handle this conversion. In this example, I would have the following transformers:
public class MessageXTransfomer()
{
public MessageX transform(MessageA message) {...}
}
public class MessageYTransfomer()
{
public MessageY transform(MessageB message) {...}
}
My questions is really with the way I would ultimately invoke the transformers.
Since my process takes some VendorMessage as an input, I need to interrogate the type so I know which specific transformer to direct it to. For example, one approach might look like this:
public class TransfomerService
{
MessageXTransformer messageXTransformer = new MessageXTransformer();
MessageYTransformer messageYTransformer = new MessageYTransformer();
public CanonicalMessage transform(VendorMessage message)
{
if (message instanceOf MessageA)
{
return messageXTransformer.transform((MessageA) message);
}
else if (message instanceOf MessageB)
{
return messageYTransformer.transform((MessageB) message);
}
}
}
I'm not sure why, but I this approach just feels strange - as if I'm doing something wrong. Is there a best practice for this kind of problem that I should be using?
Note: I'm looking for the best approach without using any transformation frameworks, etc. Ideally, the pattern would be achievable using just basic Java.
I like the answer of #javaguy however it is not complete. Of course it will be nice if you could use the specific transformer like in his later example, but if you can't you have to stick with TransformerFacade and kind of a StrategyPattern:
public class TransformerFacade {
private Map<Class, VendorMessageToCanonicalMessageTransformer> transformers = new HashMap<>();
{
// this is like strategies, the key may be class, class name, enum value, whatever
transformers.put(MessageA.class, new MessageXTransformer());
transformers.put(MessageB.class, new MessageYTransformer());
}
public CanonicalMessage transform(VendorMessage message) {
return transformers.get(message.getClass()).transform(message);
}
}
I would simply let every concrete VendorMessage return its corresponding CanonicalMessage by implementing an interface:
public interface Mapper<T> {
T map();
}
Then, MessageA should implement this interface:
public MessageA implements Mapper<MessageX> {
#Override
public MessageX map() {
MessageX message = ...;
// fill message
return message;
}
}
If you don't want to do the mapping in the VendorMessage class, then a strategy as suggested by Vadim Kirilchuk in his answer would do the trick.
Not sure if the title does this justice. I am kind of new to Java and trying to figure out how to have a single class use different "services". Let say I have an APIRequest class, this class needs to be able to use different APIs depending on what is needed. Example. I need to ship a package, if the package is below 32OZ I need to use Endicia, else I need to use FedEx. I have 2 "service" classes FedexRequest and EndiciaRequest. I am trying to allow the APIRequest class use either one depending on what the weight of the package. I created a class called APIService that has a static method called getService. it just creates a map of string name -> request class like so...
public class APIService {
private static Map<String, Object> services = new HashMap<>();
private static final Map<String, String> availableServices = new HashMap() {{
put("fedex", "FedexRequest");
put("endicia", "EndiciaRequest");
}};
public static Object getService(String type) {
if(services.containsKey(type)) {
return services.get(type);
}
return null;
}
static {
for(Map.Entry<String, String> serv : availableServices.entrySet()) {
try {
Class<?> cls = Class.forName(serv.getValue());
services.put(serv.getKey(), cls.newInstance());
} catch(Exception e) {
services.put(serv.getKey(), new Class[1]);
}
}
}
}
So now I can call APIService.getService("fedex"); however I am having a really hard time trying to figure out how to use that in my APIRequest class, because I would need to do something like...
this.service = (FedexRequest) APIService.getService("fedex");
//or
this.service = (EndiciaRequest) APIService.getService("endicia);
but that breaks the whole dynamic part of the equation, what if I need to add another service later?
I tried having both FedexRequest and EndiciaRequest implement a Request interface, then use
this.service = (Request) APIService.getService("fedex");
but that gives me a Java.lang.Class error saying it cannot be cast to Request. I am assuming it is because Request is an interface so you cannot use cls.newInstance() on an implementing class then cast to the interface.
I am really lost on how to allow my APIRequest class to use either FedexRequest or EndiciaRequest, without specifically using the type casting, so that it can be dynamic and we could add a service later without recoding the whole thing. I come from PHP where this would be extremely simple, since you do not have to explicitly define a type. Any help would be greatly appreciated. Thank you.
If I were you I would do the following:
This is the implementation of Service interface:
public interface Service {
public void performAction();
//other common functions...
}
A small modification to your APIService class:
public class APIService {
private static Map<String, Service> services = new HashMap<>();
private static final Map<String, String> availableServices = new HashMap() {{
put("fedex", "com.finity.shipping.api.fedexapi.FedexRequest");
put("endicia", "com.finity.shipping.api.endiciaapi.EndiciaRequest");
}};
public static Service getService(String type) {
return services.get(type);
}
static {
for(Map.Entry<String, String> serv : availableServices.entrySet()) {
try {
Class<?> cls = Class.forName(serv.getValue());
services.put(serv.getKey(), cls.newInstance());
} catch(Exception e) {
services.put(serv.getKey(), new Class[1]);
}
}
}
}
Every time you need a service to be added to your application just implement the Service interface:
public class FedexRequest implements Service {
public void performAction() {
//do something
}
}
And finally in your class where you use this.service:
Service service;
...
this.service = APIService.getService("fedex");
this.service.performAction();
Pooya solution is good.
I will add something. You use some strings to represent things which are typable : constants and classes. Using reflection to initialize a factory where you handle only classes written in hard in some strings(for example com.finity.shipping.api.fedexapi.FedexRequest) and belonging to your own project seems to be a overhead.
In case where your factory don't know which classes it will instantiate, using reflection is meaningful. But it seems not be the case.
Besides, FEDEX and ENDICIA could be constant by using enum. It allows to type them and to avoid bad suprpises.
We would expect that your factory be more simple. Here an example :
public class APIService {
public static enum TypeRequest{
FEDEX, ENDICIA;
}
private static Map<String, Service> services = new HashMap<>();
static {
services.put(FEDEX, new FedexRequest());
services.put(ENDICIA, new EndiciaRequest());
}
public static Service getService(TypeRequest typeRequest) {
return services.get(typeRequest);
}
}
I've currently got the following classes/interfaces laid out. The type T represents the format of data returned from DataProvider implementations. I'm using a factory so I don't need to attach type information to MyStreamingOutput. I'm using HK2 to inject the DataProviderFactory into MyStreamingOutput.
public interface DataProvider<T> {
public T next() { ... }
...
}
public final class SQLDataProvider<T> {
public SQLDataProvider(final String query, final RowMapper<T> rowMapper) { ... }
}
public interface DataProviderFactory {
public <T> DataProvider<T> getDataProvider(final String query, final RowMapper<T> rowMapper);
...
}
public final class SQLDataProviderFactory {
public <T> DataProvider<T> getDataProvider(final String query, final RowMapper<T> rowMapper) {
return new SQLDataProvider<T>(query, rowMapper);
}
}
public final class MyStreamingOutput implements StreamingOutput {
public MyStreamingOutput(final DataProviderFactory dpFactory) { ... }
#Override public void write(final OutputStream outputStream) throws IOException { ... }
}
This all works fine. Now I'm trying to set up a unit test for MyStreamingOutput, but I'm running into a couple of roadblocks. I wrote the following additional class for testing purposes:
public final class DataProviderFactoryStub implements DataProviderFactory {
private final DataProvider dataProvider;
public DataProviderFactoryStub() {
this.dataProvider = new DataProviderStub();
}
public DataProviderFactoryStub(final DataProvider dataProvider) {
this.dataProvider = dataProvider;
}
#Override
public <T> DataProvider<T> getDataProvider(final String query, final RowMapper<T> rowMapper) {
return this.dataProvider;
}
}
The binding occurs in
final class QueryTestResourceConfig extends ResourceConfig {
public QueryTestResourceConfig() {
...
this.register(new AbstractBinder() {
#Override
protected void configure() {
bind(DataProviderFactoryStub.class).to(DataProviderFactory.class);
}
});
}
}
I can successfully inject this class into MyStreamingOutput, but it has a compiler warning because the typing information used by getDataProvider() isn't shared by the instance passed into the factory. I can't add type information to the DataProviderFactoryStub class because then it no longer implements the DataProviderFactory interface. I don't want type information on the interface because it's wrong - outside of the Stub case, the factories shouldn't care about the type returned by DataProvider instances. I'd very much like to avoid using setters for the query and rowMapper parameters because I consider it bad design in this case.
I can't shake the feeling that I'm either missing something subtle in my application of generics or something obvious in my application of dependency injection. What is the right way to address this use case? It seems like this is the kind of problem DI is meant to address, but I can't see how to fix it.
When using DI, we usually end up with factory classes that are very basic (i.e., their creation methods are typically simple enough to fit on a single line). Your SQLDataProviderFactory class is a perfect example of this.
The reason for this is because a factory object is just a placeholder for the creation of an object. We want to avoid littering our code with new keywords, because doing so tightly couples code to a specific type. So we end up with factories whose methods are essentially just glorified new keywords.
I bring this up to point out that it's the type of the product that is important here; the factory is just a conduit. When you replace a factory with a test double, what you're really doing is replacing a product with a test double. This means that whenever I define a test double factory, I always have to define a test double product as well.
For example, your stub factory is just trying to return a stub product. The problem is that the type of the stub product it's returning does not match the type expected by calling code. If you define your own stub product, the code falls into place:
public final class DataProviderStub<T> implements DataProvider<T> {
private final T dummy;
public DataProviderStub() { }
public T next() { return this.dummy; } // Just for example
}
public final class DataProviderFactoryStub implements DataProviderFactory {
public DataProviderFactoryStub() { }
#Override
public <T> DataProvider<T> getDataProvider(final String query, final RowMapper<T> rowMapper) {
return new DataProviderStub<T>();
}
}
The stub factory only exists so you can inject the stub DataProvider into your SUT.
Unfortunately, due to type erasure, it isn't possible to do what I want. I will have to look at refactoring the existing code.