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.
I have the following POJO using Immutables+Jackson under the hood:
#JsonInclude(JsonInclude.Include.NON_NULL)
abstract class AbstractQueryRequest {
#JsonProperty("reqid")
public abstract String reqid();
#JsonProperty("rawquery")
public abstract String rawquery();
}
At some point I need to build another object based on the fields of the POJO, something along this line:
final HttpUrl.Builder urlBuilder = HttpUrl.parse(cfg.baseUrl()).newBuilder();
urlBuilder.addQueryParameter("reqid", request.reqid())
.addQueryParameter("rawquery", request.rawquery());
It's quite annoying to keep the POJO and this call aligned upon changes, I was wondering if it was possible to access programmatically each JsonProperty instead of typing the string manually.
Note that it is fine to write the getters by hand as I can easily refactor and I have the compiler double checking, but for strings I am worried for people down the line and I would like to "read" them from the POJO class somehow.
You can do it via reflection. You need to take method annotation values which annotated with JsonProperty. But I recommend you to use JsonProperty on fields, not methods.
Here is an example for your current requirement :
public class Main {
public static void main(String[] args) {
AbstractQueryRequest someType = new SomeType();
for(Method method : x.getClass().getSuperclass().getDeclaredMethods()) {
if (method.isAnnotationPresent(JsonProperty.class)) {
JsonProperty annotation = method.getAnnotation(JsonProperty.class);
System.out.println(annotation.value());
}
}
}
}
class SomeType extends AbstractQueryRequest {
#Override
public String reqid() {
return null;
}
#Override
public String rawquery() {
return null;
}
}
Output is :
rawquery
reqid
I'm trying to set up a Provider for DAOs created using JDBI. JDBI uses a Handle object (which is a wrapper around a JDBC Connection) and you can get hold of a DAO by using handle.attach(MyDaoType.class). Rather than having to write a separate Provider implementation for every DAO class I thought it would make sense to do this:
public class DaoProvider<T> implements Provider<T> {
private final Class<T> daoType;
private final Handle handle;
#Injected
public DaoProvider(Class<T> daoType, Handle handle) {
this.daoType = daoType;
this.handle = handle;
}
#Override
public T get() {
return handle.attach(daoType);
}
}
But it seems tremendously difficult to wire this up with Guice. I have tried using the #Assisted annotation on the 1st constructor argument as suggested in this answer. I defined a factory like this:
public interface DAOProviderFactory {
<T> DAOProvider<T> create(Class<T> daoType);
}
But it's not clear how I should invoke the FactoryModuleBuilder.implemented method as the whole point is that I don't want to have to extend my provider class.
It also seems a bit crazy that I'd have a factory that returns a provider that returns the thing I actually want!
It strikes me that this would be really easy to do with the Spring DI container so I want to believe it's possible with Guice. Can anyone point me in the right direction?
Thanks to #condit for pointing me at something that enabled me to solve the issue. It's actually very simple. I changed the Provider implementation to use field injection for the Handler like this:
public class DAOProvider<T> implements Provider<T> {
private #Inject Handle handle;
private final Class<T> daoType;
public DAOProvider(Class<T> daoType) {
this.daoType = daoType;
}
#Override public T get() {
return handle.attach(daoType);
}
}
Then in any module or application where I have specific DAO classes I want to bind I can just do something like this:
bind(UserStore.class).toProvider(new DAOProvider<>(UserStore.class));
bind(MessageStore.class).toProvider(new DAOProvider<>(MessageStore.class));
Guice then injects the Handle into the DAOProvider instances automatically.
I think you're making this far too complicated. When you call the get() method, you are storing the result in a reference, which means you know the type of the particular DAO, which means you can write your code knowing the DAO class. I mean, think about how Guice itself works, you call Injector.getInstance(Class<?> type)... in other words, methods like this can't infer the type without you passing the Class anyway, so pass the Class when you use it!
I can understand why you might not want to inject Handle directly though, so why not just make a wrapper, e.g.
public interface DaoProvider {
<T> T provideDao(Class<T> daoType);
}
And then:
public class JdbiDaoProvider implements DaoProvider {
private final Handle handle;
#Inject
JdbiDaoProvider(Handle handle) {
this.handle = handle;
}
public <T> T provideDao(Class<T> daoType) {
return handle.attach(daoType);
}
}
I am trying to build a factory object, but having trouble working out a good way of doing it in Java.
The application I am writing is used for processing files in various formats, so there is a CodecInterface which applies to all classes which are used for reading and writing files. Let's assume it defines the following methods. Each of these files has a unique human-designated ID string which is used for id'ing the encoder\decoder.
String read();
void write(String data);
String getID();
The factory class would have a create method which is intended to create instances of these codec classes. I imagine the method signature would look something like this.
static CodecInterface CodecFactory.create(String filename, String codecid, String args);
The filename is the name of the file to read/write, and the codecid is the unique ID indicating what codec to use. The args parameter is a string of arguments passed to the decoder/encoder object being generated. The return of this should be an instance of the requested codec object.
All of the Factory examples I have seen typically have a switch statement inside of the create method which creates an object instance dependent on the ID. I want to avoid doing it this way as it doesn't seem like the 'right' way, and it also means that the list is more or less fixed unless you modify the create method. Ideally I would like to use something like a dictionary (indexed by the codec ID) which contains something which can be used to create an instance of the codec classes I want (I will call this mystery class ClassReference). Again to use some quasi-java code, here is what I was thinking as the body for the create method.
static Dictionary<String, ClassReference>;
static CodecInterface CodecFactory.create(String filename, String codecid, String args);
{
ClassReference classreference;
classreference = codeclibrary(codecid);
return classreference.instanceOf(args);
}
The dictionary of ID's is easy enough, but I can't work out what ClassReference should be. Class Reference should allow me to create an instance of the desired class, as in the example above.
From looking around online, the class method, and instanceOf seem to be heading in the right direction, but I haven't found anything which puts the two together. As an added complication, the constructors for the objects being created will have arguments.
Any tips on what I should be looking at would be greatly appreciated.
Thanks in advance.
SOLUTION
Thanks everyone for your advice. I've ended up taking bits and pieces from all of your suggestions and came up with the following which seems to work as I wanted.
Note that I have omitted much of the sanity\error checking code to show off the important bits.
import java.lang.reflect.Constructor;
import java.util.HashMap;
public class CodecFactory
{
private static HashMap<String, Class<? extends CodecInterface>> codecs;
static
{
codecs = new HashMap<String, Class<? extends CodecInterface>>();
//Register built-in codecs here
register("codecA", CodecA.class);
register("codecB", CodecB.class);
register("codecC", CodecC.class);
}
public static void register(String id, Class<? extends CodecInterface> codec)
{
Class<? extends CodecInterface> existing;
existing = codecs.get(id);
if(existing == null)
{
codecs.put(id, codec);
}
else
{
//Duplicate ID error handling
}
}
public static CodecInterface create(String codecid, String filename, String mode, String arguments)
{
Class<? extends CodecInterface> codecclass;
CodecInterface codec;
Constructor constructor;
codec = null;
codecclass = codecs.get(codecid);
if(codecclass != null)
{
try
{
constructor = codecclass.getDeclaredConstructor(String.class, String.class, String.class, String.class);
codec = (CodecInterface)(constructor.newInstance(codecid, filename, mode, arguments));
}
catch(Exception e)
{
//Error handling for constructor/instantiation
}
}
return codec;
}
}
There's a zillion options. For example, you might create a base factory class that also has static methods to manage registered factories (untested code typed here, sorry for errors):
public abstract class CodecFactory {
private final String name;
public CodecFactory (String name) {
this.name = name;
}
public final String getName () {
return name;
}
// Subclasses must implement this.
public abstract Codec newInstance (String filename, String args);
// --- Static factory stuff ---
private static final Map<String,CodecFactory> factories = new HashMap<String,CodecFactory>();
public static void registerFactory (CodecFactory f) {
factories.put(f.getName(), f);
}
public static Codec newInstance (String filename, String codec, String args) {
CodecFactory factory = factories.get(codec);
if (factory != null)
return factory.newInstance(filename, args);
else
throw new IllegalArgumentException("No such codec.");
}
}
Then:
public class QuantumCodecFactory extends CodecFactory {
public QuantumCodecFactory {
super("quantum");
}
#Override public Codec newInstance (String filename, String args) {
return new QuantumCodec(filename, args);
}
}
Of course this means at some point you must:
CodecFactory.registerFactory(new QuantumCodecFactory());
Then usage is:
Codec codec = CodecFactory.newInstance(filename, "quantum", args);
Another option is to use reflection and maintain a Map<String,Class<? extends CodecInterface>>, using Class.newInstance() to instantiate. This is convenient to implement because it works on top of Java's Class, which already supports a factory-style model for instantiating objects. The caveats are, like above the classes must be explicitly registered, and also (unlike above) you can't implicitly enforce constructor parameter types at compile-time (although you could at least abstract it behind some method instead of calling Class.newInstance() directly from client code).
For example:
public final class CodecFactory {
private static final Map<String,Class<? extends Codec>> classes = new HashMap<String,Class<? extends Codec>>();
public static void registerClass (String name, Class<? extends Codec> clz) {
classes.put(name, clz);
}
public static Codec newInstance (String filename, String codec, String args) {
Class<? extends Codec> clz = classes.get(codec);
if (clz != null)
return clz.getDeclaredConstructor(String.class, String.class).newInstance(filename, args);
else
throw new IllegalArgumentException("No such codec.");
}
}
Where every Codec is expected to have a constructor that takes (String filename, String args). Registration, then, is:
CodecFactory.registerClass("quantum", QuantumCodec.class);
Usage is the same as above:
Codec codec = CodecFactory.newInstance(filename, "quantum", args);
You could even leave out the map and just use Class.forName() -- this doesn't give you as much flexibility with codec names, but it essentially lets the class loader do all of the work for you and you don't need to explicitly register types ahead of time.
Edit: Re: Question in comments below. You could come up with a system that combined the two above examples to create a reusable, reflection based generic factory derived from CodecFactory, which still leaves you with the ability to create other more specialized factories, e.g.:
public class GenericCodecFactory extends CodecFactory {
private final String name;
private final Class<? extends Codec> clz;
public GenericCodecFactory (String name, String clzname) {
this.name = name;
this.clz = Class.forName(clzname);
}
public GenericCodecFactory (String name, Class<? extends Codec> clz) {
this.name = name;
this.clz = clz;
}
// parameter type checking provided via calls to this method, reflection
// is abstracted behind it.
#Override public Codec newInstance (String filename, String args) {
return clz.getDeclaredConstructor(String.class, String.class).newInstance(filename, args);
}
}
Then you could use that for whatever:
// you can use specialized factories
ClassFactory.registerFactory(new QuantumCodecFactory());
// you can use the generic factory that requires a class at compile-time
ClassFactory.registerFactory(new GenericCodecFactory("awesome", AwesomeCodec.class));
// you can use the generic factory that doesn't need to have class present at compile-time
ClassFactory.registerFactory(new GenericCodecFactory("ninja", "com.mystuff.codecs.NinjaCodec"));
As you can see, there's a ton of possibilities. Using Class.forName() in reflection-based factories is nice because the class doesn't need to be present at compile-time; so you can drop in codec classes on the class path and, say, specify a list of class names in a run-time configuration file (then you could have static ClassFactory.registerFactoriesListedInFile(String confgFilename) or something), or scan a "plugin" directory. You can even construct class names from simpler strings, if you're comfortable with that, e.g.:
public class GenericPackageCodecFactory extends GenericCodecFactory {
public GenericPackageCodecFactory (String name) {
super(name, "com.mystuff." + name + ".Codec");
}
}
You could even use something like that as a fallback in ClassFactory if the codec name is not found, to get around having to explicitly register types.
The reason reflection keeps popping up, by the way, is that it's very flexible and the Class interface is essentially an all-encompassing class factory, so it frequently parallels what specific factory architectures are trying to accomplish.
Another option is to use the second example I mentioned above (with the Map<String,Class>) but make a version of registerFactory that takes a String class name instead of a Class, similar to the generic implementation I just mentioned. That's probably the least amount of code required to avoid having to create instances of CodecFactorys.
I can't possibly give examples for every combination of things you can do here, so here is a partial list of the tools you have available, which you should use as you see fit. Remember: Factories are a concept; it's up to you to use the tools you have to implement that concept in a clean way that meets your requirements.
Reflection (Class<?> and Class.forName)
Static initializer blocks (sometimes a good place to register a factory; requires class to be loaded, but Class.forName can trigger this).
External configuration files
Plugin frameworks like http://jpf.sourceforge.net/ or https://code.google.com/p/jspf/ or https://code.google.com/p/jin-plugin/ (good comparison of OSGi, JPF, JSPF can be found here; I've never heard of jin-plugin prior to looking through the answers in the link).
Maps of registered factories and/or ability to use reflection to generate class names on the fly.
Don't forget concurrent maps and/or synchronization primitives for multi-threaded support if necessary.
Lots of other stuff.
Also: Don't go crazy implementing all of these possibilities if you don't have to; think about your requirements and decide on the minimum amount of work you need to do here to meet them. For example, if you need extensible plugins, JSPF alone might be enough to satisfy all of your requirements without you having to do any of this work (I haven't actually checked it out, so I'm not sure). If you don't need that kind of plugin "scanning" behavior, simple implementations like the examples above will do the trick.
Try something like that:
public class CodecFactory {
final private static Map<String, Class<? extends CodecInterface>> codecLibrary;
static {
codecLibrary = new HashMap<String, Class<? extends CodecInterface>>();
codecLibrary.put("codec1", Codec1.class);
//...
}
static CodecInterface create(String filename, String codecid, String args) throws InstantiationException, IllegalAccessException {
Class<? extends CodecInterface> clazz;
clazz = codecLibrary.get(codecid);
CodecInterface codec = clazz.newInstance();
codec.setArgs(args);
codec.setFilename(filename);
return codec;
}
}
You can use enum as well, just like below :
interface CodecInterface {
}
class CodecA implements CodecInterface {
}
class CodecB implements CodecInterface {
}
class CodecC implements CodecInterface {
}
enum CodecType {
codecA {
public CodecInterface create() {
return new CodecA();
}
},
codecB {
public CodecInterface create() {
return new CodecB();
}
},
codecC {
public CodecInterface create() {
return new CodecC();
}
};
public CodecInterface create() {
return null;
}
}
class CodecFactory {
public CodecInterface newInstance(CodecType codecType) {
return codecType.create();
}
}
I am trying to create a class that is responsable for managing all the database access of my application, controlling the API of my DAO objects that have all protected methods. Some indentifiers are in portuguese since I'm a brazilian, anyways I think you will be able to understand whats going on there.. Following is the code:
public class DatabaseManager {
private ItemExpansivelDataSource itemExpansivelDataSource;
private ConfiguracoesDashboardDataSource configuracoesDashboardDataSource;
private PranchaDataSource pranchaDataSource;
private PranchaRaizDataSource pranchaRaizDataSource;
private HashMap<Class<?>, DataSource<?>> dataSourcesMap;
public DatabaseManager() {
super();
this.dataSourcesMap = new HashMap<Class<?>, DataSource<?>>();
dataSourcesMap.put(ItemExpansivel.class, itemExpansivelDataSource);
dataSourcesMap.put(ConfiguracoesDashboard.class, itemExpansivelDataSource);
dataSourcesMap.put(Prancha.class, itemExpansivelDataSource);
dataSourcesMap.put(PranchaRaiz.class, itemExpansivelDataSource);
}
public void insert(Object objeto){
if(dataSourcesMap.containsKey(objeto.getClass())) {
return dataSourcesMap.get(objeto.getClass()).insert(objeto);
} else {
throw new RuntimeException(ErrorMessages.NAO_EXISTE_DATA_SOURCE.toString());
}
}
and there is the declaration of my datasource
public interface DataSource<T> {
List<T> getAll();
T findById(Integer id);
void openConection();
void closeConection();
void update(T valor);
void update(List<T> valores);
T insert(T valor);
List<T> insert(List<T> valores);
void delete(T valor);
void delete(List<T> valores);
Integer getLastInsertedRowId();
T converter(Cursor cursor);
}
My problem is that java dont know what kind of object it will receive as parameter so I cant call the insert method as I am trying to do, I need to find a work around but I cant think on nothing.. I wish someone can bring me some light, because I really think this is a good aproach to control the API of my DAO objects.. Thanks a lot
The only way to make it type-safe is to add a method to your DataSource interface which returns the required type, i.e:
Class<T> getDataType();
Then you can turn your Map operations into type-safe code by introducing a helper method per operation:
public Object insert(Object objeto){
final DataSource<?> dataSource = dataSourcesMap.get(objeto.getClass());
if(dataSource!=null) {
assert dataSource.getDataType().isInstance(objeto);
return doInsert(dataSource, objeto);
} else {
throw new RuntimeException(ErrorMessages.NAO_EXISTE_DATA_SOURCE.toString());
}
}
private static <T> T doInsert(DataSource<T> ds, Object o) {
return ds.insert(ds.getDataType().cast(o));
}
The only way without such a method is to work without type safety. If your Map is private and you maintain the mappings correctly so that you always have a valid Class-key → value’s type parameter relationship this could be an option. In this case, use the helper method as above but replace the ds.getDataType().cast(o) by an unsafe type-cast: (T)o.