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();
}
}
Related
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 two classes CashStore and DrinkStore, both extends from Store. I have a StoreFactory class (returns Store object) to instantiate objects for clients. I want to access methods specific to child classes from these clients. How do I do it without casting? If I used casting, would it break the pattern, since now the clients know about the Child classes?
class Store{
A(){}
B(){}
}
class CashStore{
A(){}
B(){}
C(){}
D(){}
}
//impl for drink store and other stores
class StoreFactory{
public Store getStore(String type){
//return a Store obj based on type DrinkStore or CashStore
}
}
class Client{
StoreFactory fac;
public Client(){
fac = new StoreFactory();
Store s = fac.getStore("cash");
s.C(); //requires a cast
}
}
Does casting break my pattern?
Factory pattern is used to decouple from runtime type. For example, when it's platform- or layout-specific, and you don't want your client code to mess with it. In your case you do need an exact type, so it seems factory pattern isn't a good choice. Consider using simple static methods, like:
class Stores {
static CashStore createCashStore() {
return new CashStore();
}
static DrinkStore createDrinkStore() {
return new DrinkStore();
}
}
So basically you need to access child specific methods without casting. That's the whole purpose of Visitor pattern.
You can switch between different child by using method overloading. I have given an example below, you would need to adapt that to fit into your code. And also you should take out the business logic from the constructor (of Client) and implement them inside methods.
public class Client{
public void doSomething(CashStore cs){
cs.c();
//you can call methods specific to CashStore.
}
public void doSomething(DrinkStore ds){
ds.e();
//you can call methods specific to DrinkStore.
}
}
I want to access methods specific to child classes from these clients.
How do I do it without casting?
If you know the expected type, then you can use generics to avoid casting:
interface Store {
}
class WhiskeyStore implements Store {
}
class VodkaStore implements Store {
}
class StoreFactory {
<T extends Store> T getStore(Class<T> clazz) {
try {
// I use reflection just as an example, you can use whatever you want
return clazz.getConstructor().newInstance();
} catch (Exception e) {
throw new RuntimeException("Cannot create store of type: " + clazz, e);
}
}
}
public final class Example {
public static void main(String[] args) {
WhiskeyStore whiskeyStore = new StoreFactory().getStore(WhiskeyStore.class);
VodkaStore vodkaStore = new StoreFactory().getStore(VodkaStore.class);
}
}
Essentially what I'm trying to do is create a generic method that can take many different kinds of enums. I'm looking for a way to do it how I'm going to describe, or any other way a person might think of.
I've got a base class, and many other classes extend off that. In each of those classes, I want to have an enum called Includes like this:
public enum Includes {
VENDOR ("Vendor"),
OFFERS_CODES ("OffersCodes"),
REMAINING_REDEMPTIONS ("RemainingRedemptions");
private String urlParam;
Includes(String urlParam) {
this.urlParam = urlParam;
}
public String getUrlParam() {
return urlParam;
}
}
I've got a method that takes in a generic class that extends from BaseClass, and I want to be able to also pass any of the includes on that class to the method, and be able to access the methods on the enum, like this:
ApiHelper.Response<Offer> offer = apiHelper.post(new Offer(), Offer.Includes.VENDOR);
public <T extends BaseClass> Response<T> post(T inputObject, Includes... includes) {
ArrayList<String> urlParams = new ArrayList<String>();
for (Include include : includes){
urlParams.add(include.getUrlParam());
}
return null;
}
Is there a way to be able to pass in all the different kinds of enums, or is there a better way to do this?
---EDIT---
I've added an interface to my enum, but how can I generify my method? I've got this:
public <T extends BaseClass> Response<T> post(Offer inputObject, BaseClass.Includes includes) {
for (Enum include : includes){
if (include instanceof Offer.Includes){
((Offer.Includes) include).getUrlParam();
}
}
return null;
}
But I get an error on apiHelper.post(new Offer(), Offer.Includes.VENDOR); saying the second param must be BaseClass.Includes.
Enums can implement interfaces, so you can create an interface with these methods that you'd like to be able to call:
interface SomeBaseClass {
String getUrlParam();
void setUrlParam(String urlParam);
}
and then your enum can implement this interface:
public enum Includes implements SomeBaseClass {
VENDOR ("Vendor"),
OFFERS_CODES ("OffersCodes"),
REMAINING_REDEMPTIONS ("RemainingRedemptions");
private String urlParam;
Includes(String urlParam) {
this.urlParam = urlParam;
}
#Override
public String getUrlParam() {
return urlParam;
}
#Override
public void setUrlParam(String urlParam) {
this.urlParam = urlParam;
}
}
If you want to get really fancy, it's possible to restrict subtypes of the interface to enums, but the generic type declaration will be pretty ugly (thus hard to understand and maintain) and probably won't provide any "real" benefits.
Unrelated note regarding this design: it's a pretty strong code smell that the enum instances are mutable. Reconsider why you need that setUrlParam() method in the first place.
In my program, I've got the following class hierarchy:
public abstract class Effect
{
// ...
}
public class Effect1 extends Effect
{
public static final NAME = "blah blah 1";
// ...
}
public class Effect2 extends Effect
{
public static final NAME = "blah blah 2";
// ...
}
(many more EffectN classes with quite different implementations). Later on, I've got another family of classes using those EffectN's :
public abstract class EffectList
{
protected Effect mEffect;
// ...
}
public class EffectList1 extends EffectList
{
public static final N = Effect1.NAME;
public EffectList1
{
mEffect = new Effect1();
}
// ...
}
public class EffectList2 extends EffectList
{
public static final N = Effect2.NAME;
public EffectList2
{
mEffect = new Effect2();
}
// ...
}
(many more of those EffectListN classes, one for each EffectN).
Now, while the EffectN's really do have quite different implementations, all the EffectListN's are (nearly) identical - the only difference between them is shown above.
Now, had this been C++, all the EffectListN classes would be easily generated with just 1 template, but AFAIK (being quite new to Java) Java generics cannot do this job, can it?
Any suggestions?
Are you trying to create generic way to call constructor? If so this could be done by reflection as long as all implementation would supply the same kind of arguments e.g. default constructor:
class EffectList<EffectType extends Effect> {
public EffectList(Class<EffectType> clazz) {
try {
mEffect = clazz.getConstructor().newInstance();
} catch (Exception ex) {
// suppressing Exceptions - in production code you should handle it better
throw new RuntimeException(ex);
}
// ...
}
// ...
}
then use it like that:
EffectList<Effect1> effectList1 = new EffectList(Effect1.class);
EffectList<Effect2> effectList2 = new EffectList(Effect2.class);
The static field however cannot be handled such way - best you can do is make it an instance variable and obtain the value via reflection as well:
clazz.getDeclaredField("NAME").get(null); // null is used to obtain static fields
Reason why static field cannot be handled is that there would be only one variable shared among all EffectLists (since underneath its only just one class with just compile-time checks added).
I don't know how you would do it with C++, but going off your description, no, Java generics would not be able to handle this.
For one, you have static fields that depend on other static fields defined in the EffectN types. There's nothing in Java which sets a restriction that a type should have a static field. You wouldn't be able to dynamically set
public static final N = SomeEffect.NAME;
Second, because of type erasure, you would not be able to do
public EffectList2
{
mEffect = new SomeEffect(); // assuming SomeEffect is the type parameter
}
you'd need to pass in a Class instance and use reflection to instantiate this type.
I want to make a refactoring and want to create a generic class for avoiding duplicate code. We have many XXXCriteriaValidator in our project and we want to make one only unique class to substitute them all.
The problem is one line where this class calls for a static method from an Enum. Here you will see. This is more or less what I'mtrying to achieve:
public class GenericCriteriaValidator<T extends ¿SomeKindOfEnumInterface?>
implements CriterionVisitor {
protected Errors errors;
public Errors getErrors() {
return this.errors;
}
/*
* Some code around here
*/
protected void doVisit(final PropertyCriterion criterion) {
if (criterion == null) {
this.errors.reject("error.criterion.null");
} else {
if (criterion.getOperator() == null) {
this.errors.reject("error.operator.null");
}
// Validates property (exception thrown if not exists)
T.fromString(criterion.getName()); // The problem is this call here!!
// Not saying this compiles, just looking
// how to do something equivalent
}
}
}
T is always a differente Enum. The typical enum is like this:
public enum ContactCriteria implements CriteriaInterface<ContactCriteria> {
// ^ This interface is added by me
// for the enum being called in the previous class
CONTACT_ID("this.id"),
CONTACT_COMPANY_ID("this.companyId"),
CONTACT_NAME("this.name"),
CONTACT_EMAIL("this.email"),
CONTACT_PHONE_NUMBER("this.phoneNumber"),
CONTACT_ORDER("this.order"),
private final String alias;
ContactCriteria(final String alias) {
this.alias = alias;
}
public String getAlias() {
return this.alias;
}
public static ContactCriteria fromString(final String name) {
ContactCriteria result = null;
if (name != null) {
result = Enum.valueOf(ContactCriteria.class, name);
}
return result;
}
public ContactCriteria returnThis() {
return this;
}
}
Finally, I'm looking for making an interface for the first class to accept the fromString method of T. I suppose it should be similar to:
public interface CriteriaInterface<T> {
static T fromString(String name);
// ^ This static is important
}
I haven't found none post or strategy for making something similar with an Enum. I know the Enum can implement an interface, but don't know how to get it.
Please help. Thanks in advance
You should start with that a static method is not allowed in Java interface.
The concept behind interfaces strongly disagree with static elements as they belong to class not to object.
So if you have a static method in a enum is just a container that is assigned to but you should not connect it by any other relations.
What is bad here is the design, you try to use enum to something that the are not dedicated on in the way you should not that why you struggle so much.
The question is if a enum instance is an CriteriaInterface then why is should provide it self by name.
Enum contains definition of "constants" that can represent an interface but can not be generic. That why enum can implement interface.
To express that you can define a interface
interface Messanger {
String getMessage();
}
And try to apply it to enum
enum Messages {
INFO
WARNING;
}
You have two options,
First, create a field that will be
enum Messages implements Messanger {
INFO,
WARNING;
private String message;
#Override
public String getMessage() {
return message;
}
}
Then you have to add the constructor to set the field
enum Messages implements Messanger {
INFO("Info"), //We create an instance of class as we call the constructor
WARNING("Warnig") //We create an instance of class as we call the constructor
;
private final String message;
public Message(String message) {
this.messsage = message;
}
#Override
public String getMessage() {
return message;
}
}
As we declare the instances inside the body of the enum you must provide all information required to create it. Assuming that enum would allow generic this is the place where you should declare it.
If the static method is on your CriteriaInterface, shouldn't you do
CriteriaIntervace.fromString("")
since static methods belong to a class (in this case CriteriaIntervace) instead of to an object?
You can't put static methods in an interface, the generics etc have no direct bearing on this. Interfaces define the methods of an instance of an object, static methods are not part of the interface of an instance, they are part of the interface of the class.
The easiest work around will be to provide a factory object to the GenericCriteriaValidator or make it abstract and provide an:
abstract T getEnum(String name);
Each implementation can then implement getEnum for the enum it is using.
Well, generally speaking, the generic type is erased and you have no other chance than explicitly telling the GenericCriteriaValidator what kind of validation logic it should apply. You might want to abstract the receiving of some type away and use a factory pattern for that what would allow you to define an interface for the fromString method.
This would result in something like this:
public interface CriteriaInterface<T> {
static class Factory<U> {
U fromString(String name);
}
}
However, I do not quite see the benefit of that in your example. Simply require an instance of CriteriaInterface<T> as a constructor argument to your GenericCriteriaValidator and define some sort of validate method in this interface.
However, if you really, really want to avoid this, there is a solution. It is possible to read the generic type of the super class of some other class (this is rather hacky, requires reflection and I would not recommend it, but some libraries love this approach). This requires you to always declare an anonymous subclass when using your generic class:
class GenericCriteriaValidator<T extends Enum<?>> implements CriterionVisitor {
private final Method criteria;
public GenericCriteriaValidator() {
ParameterizedType parameterizedType = (ParameterizedType) getClass()
.getGenericSuperclass();
try {
criteria = ((Class<?>) parameterizedType.getActualTypeArguments()[0])
.getMethod("fromString", String.class);
criteria.setAccessible(true);
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException(e);
}
}
#SuppressWarning("unchecked")
private CriteriaInterface<?> invokeFromString(String value) {
try {
return (CriteriaInterface<?>) criteria.invoke(null, value);
} catch (IllegalAccessException e) {
throw new IllegalStateException(e);
} catch (InvocationTargetException e) {
throw new IllegalArgumentException(e);
}
}
// Your other code goes here.
}
Be aware that you need to instantiate your GenericCriteriaValidator as an anonymous subclass:
new GenericCriteriaValidator<ContactCriteria>() { }; // mind the braces!
As I said. I do not find this intuitive and it is most certainly not the "Java way", but you might still want to consider it.