Factory Design Pattern - defining methods in subclasses - java

I'm implementing a factory a class in charge of managing tokens across an application. I'll explain the problem I'm facing after this simplified example:
Suppose we have our factory class:
TokenManagerFactory.java:
public class TokenManagerFactory {
public static TokenManager create(String tokenType)
{
if ("JWT".equals(tokenType))
return new JwtTokenManagerImpl();
return null;
}
}
Then our abstract interface:
public abstract interface TokenManager {
public String generateToken();
public boolean verifyToken();
}
And finally the implementation JwtTokenManagerImpl:
public class JwtTokenManagerImpl implements TokenManager {
//..Implementation of methods defined in interface (generateToken() and
// verifyToken())
public String aMethodNotDefinedInInterface() {
return "A very cool String";
}
}
Now in our main we want to create an instance of JwtTokenManager:
main {
TokenManager tm = TokenManagerFactory.create("JWT");
tm.aMethodNotDefinedInInterface(); // <-- Compilation error.
}
The method aMethodNotDefinedInInterface() is undefined for the type
TokenManager
How do I adjust this design pattern so this error does not occur? Downcasting for when doing such calls seems like a harsh solution, is there a higher level adjustment I could make to accommodate this scenario?
Thanks.
I marked the solution I ended up using.

How do I adjust this design pattern so this error does not occur?
You have to make a choice : either working with a base common type to manipulate all subclasses in an uniform way from the API of the base common type or casting it to a specific type to be able to invoke specific method of a subclass.
Some ideas to solve your issue :
Add the method in the interface.
If the method is expected for some implementations but not for all you could add it in the interface with a default implementation (that throws UnsupportedOperationException for example). You could override it in the subclass that wants to support it.
It will work but will also do your code more brittle as the exception would be throw only at runtime.
Provide an additional factory method that returns the concrete subclass in its declaration.
Or as alternative enrich the actual method to return a generic type inferred by the target type specified in the return of the invoker. It is not type safe but it spares an explicit cast.
It would give something like :
#SuppressWarnings("unchecked")
public static <T extends TokenManager> T create(String tokenType) {
if ("JWT".equals(tokenType)) {
return (T) new JwtTokenManagerImpl();
}
return null;
}
That you invoke :
JwtTokenManagerImpl token = create("JWT");
Use the decorator pattern to enrich the behavior of some objects if it matches to your need. You should rely on a common method in TokenManager that the decorator will enrich.
You could so write something like :
TokenManager tm = new TokenFooDecorator(TokenManagerFactory.create("JWT"));

You could change TokenManagerFactory to accept an interface instead?
public interface JwtTokenManager extends TokenManager {
String aMethodNotDefinedInInterface();
}
public class TokenManagerFactory {
public static <T extends TokenManager> T create(Class<T> managerInterface) {
if (managerInterface == JwtTokenManager.class) {
return (T) new JwtTokenManagerImpl();
}
return null;
}
}
Then where you use the factory can be something like:
public static void main(String[] args) {
JwtTokenManager tm = TokenManagerFactory.create(JwtTokenManager.class);
tm.aMethodNotDefinedInInterface();
}

If aMethodNotDefinedInInterface() is required for all Token managers, then it should be added to the interface.
Otherwise, this suggests that you need a different flow for each Token Manager, in which case you might want to use the Bridge design pattern.
In this case, the Implementor hierarchy will be the token managers, and the Abstraction hierarchy will consist of the different flows implementations.
Then you can match the flow you want with the token implementation you want.
You'll still need to add the method to the interface, and either:
Add an empty implementation where its not relevant.
Throw UnsupportedOperationException exception, indicating that the flow/token manager combination is illegal.

I am going to talk about what is wrong with your design first:
Here is your code:
TokenManager tm = TokenManagerFactory.create("JWT");
tm.aMethodNotDefinedInInterface(); // <-- Compilation error.
The question is, why does the create method take a token when you only have one possible value for that token? You might as well always return the concrete type.
You are going to tell me that you might want to do this:
String token = getTokenFromSomewhere(); // it may or may not be JWT
TokenManager tm = TokenManagerFactory.create(token);
tm.aMethodNotDefinedInInterface(); // <-- Compilation error.
In that case, you don't know what type of TokenManager you have returned, so you can't call a method on it unless it is in the interface.
You might now say that you would want to do either of the two cases - with a known token or an unknown token. In this case, the known token case is a bit of a mis-use of the factory method since its design is to return any type of token. You are using the factory in two different ways. You could therefore either create a specific factory method for the particular token, or just use a cast.

A method Not Defined In the Interface, cannot be invoked using the Interface type. So the reference variable tm of Interface type TokenManager has to be cast to one of the sub type, before invoking the specific method(that is not in the interface, but in the specific class).
if (tm instanceof JwtTokenManagerImpl ) {
JwtTokenManagerImpl jwtTm = (JwtTokenManagerImpl) tm;
jwtTm.aMethodNotDefinedInInterface();
}

Related

Get all types of a Decorator Object: type of wrapped objects and the type of wrapper object

So, this is my design. AccessDecorator classes have a reference to another Access just like normal Decorator Pattern.
But the problem is when I create an AccessDecorator wrapping a ConcreteAccess and then try to see which type the Access is:
Access access = new InAllowedAccess();
Access wrapperAccess = new MismatchAccess(access);
if (wrapperAccess instanceof InAllowedAccess) //this condition could be used to be a predicate for a filtering over an access list for example
//do something
Of course this won't work because wrapperAccess is not of type InAllowedAccess but what I really want to know is all the types of some Access. In this case, the wrapperAccess would be not only of type MismatchAccess but also of type InAllowedAccess
I thought about implementing methods like isInstanceofInAllowed(), isInstanceofOutAllowed(), isInstanceofInDenied() and isinstanceofOutDenied(), isinstanceofMismatch() in Access classes but don't seems a good solution, I don't know...
Otherwise should I create a big hierarchical tree with MismatchAccesses for each 4 types InAllowedMismatchAccess, OutAllowedMismatchAccess, InDeniedMismatchAccess and OutDeniedMismatchAccess? And then, when I develp another decorator?...
Or is there another better design?
How can I know all the types of an Access? Not only the type of the wrapper access but also the type of the wrapped access.
EDIT:
One of my needs is: filter a collection of Accesses by their type - ÌnAllowedAccess, InDeniedAccess, OutAllowedAccess, OutDeniedAccess, MismatchAccess (which is a decorator) and other types of decorators that I might develop
Avoiding type checking is the usually the best way to do things. Unfortunately you haven't given enough context how you are going to use your classes so that I can give an example on how you can use polymorphism and avoid it.
Adding type checking will limit the ability of your system to grow because as new classes are added, these types need to be included in your type checks. Sometimes this can lead to bugs as your code can make assumptions of the number of classes or their types. Here's an example:
Note: I just made this up for illustrational purpose. It's not about having to represent your logic or anything like that.
public void someMethod(Access access) {
if(access instance of InAccess) {
InAccess inAccess = (InAccess)access;
}
else {
OutAccess outAccess = (OutAccess)access;
}
}
When we started our system had two classes that inherit from Access. Assume that we add another Access class to our system. This code will crash on the else because we may pass the new third access type and the cast won't succeed.
Of course this isn't always the case. Sometimes the number of classes that you have won't grow too much. It's possible that you can predict all types that will have.
And of course, since all things can happen in programming, sometimes you do need to know the types of objects you are using.
Let's assume that your system do need to know the type of objects. Here are two solutions:
Add an enum that will represent all types that you have.
public enum AccessType {
InAccessAllowed,
InAccessDenied,
OutAccessDenied,
// other types
}
public interface Access {
AccessType getType();
// other stuff
}
This way you will use the enum AccessType instead of type casting.
Use interfaces.
Instead of using classes define an interface for each type of Access. Then you will check for the interfaces instead of classes. This way your decorators can implement the same interface as the class it decorates.
public interface InAllowedAccess { }
public class InAllowedAccessImp implements InAllowedAccess { }
public class InAllowedAccessDecorator implements InAllowedAccess { }
I just wan't give an example of an alternative implementations. Since context is lacking in your description, I'll just try to guess how you are going to use your classes and add behavior to them. It's just an idea an nothing more.
Let's assume that your system grant access to users. Users can be given In and Out access and some part of your system need to ask if an access is granted or denied to a specific user so that it can execute a specific logic.
If you don't have any behavior associated with your Access classes you can just use it as a descriptor that will carry the information necessary for other classes to do their jobs.
public enum PortType { In, Out }
public enum Permissions { Allowed, Denied }
public class Access {
private PortType mPortType;
private Permissions mPermissions;
public Access(PortType portType, Permissons permissions) {
mPortType = portType;
mPermissions = permissions;
}
public PortType getType() { return mPortType; }
public Permissions getPermissions() { return mPermissions; }
}
If you do have behavior, then you can use polymorphism. Define the behavior in your Access interface and let classes that impelement this interface define the behavior.
Let's say we have messaging system that a user can receive (In) and send (out) messages. These messages go trough a channel. These channels will either accept or reject messages. Here's a way you can use polymorphism instead of type checking.
public interface MessageChannel {
public bool canSendMessages(); // out
public bool canReceiveMessages(); // in
public void receiveMessage(Message m);
public void sendMessage(Message m);
}
public class InMessageChannel implements MessageChannel {
// out messaging is not allowed, cannot send
public bool canSendMessages() { return false; }
// In messaging allowed, can receive
public bool canReceiveMessages() { return true; }
public void sendMessage(Message m) {
throw new SendingMessagesIsNotAllowd();
}
public void receiveMessage(Message m); {
// do something with the mssage
}
}
public class OutMessageChannel implements MessageChannel {
// out messaging allowed
public bool canSendMessages() { return true; }
// In messaging not allowed
public bool canReceiveMessages() { return false; }
public void sendMessage(Message m) {
// send the message
}
public void receiveMessage(Message m); {
throw new ReceivingMessagesIsNotAllowd();
}
}
As you can see each MessageCahnnel has a behavior accosiated with it. It can either send of receive messages if it's allowed or not. This way other classes that use the MessageChannel won't have to do type casting.
I thought about implementing methods like isInstanceofInAllowed(), isInstanceofOutAllowed(), isInstanceofInDenied() and isinstanceofOutDeniedd() in Access classes but don't seems a good solution, I don't know...
You are right. That’s a bad solution. An interface often belongs to a layer with high level of abstraction in software, thus the list of its methods should be stable. If you put such a bunch of methods like above into the Access interface, the interface would be very unstable since in the future it’s very likely that you will add more such methods to it.
The simplest solution to your problem is adding (only one time) a new method named core() to the Access interface. Every decorator just implements this method by returning the wrapped/core object.
interface Access {
...
Access core();
}
Access a = ...
if (a.core() instanceof ...

Java Method return concrete type from generic return type

I am trying to make an enum list, and have an abstract method defined in the enum, which each enum value implements. The problem I am facing is that the abstract class has a generic return type but I want each enum value to return a concrete type.
I'll give an example:
public enum Attributes {
name {
#Override
public void createAttribute(Person person) {
//Do some validations
//Save in some storage
}
#Override
public Name getAttribute(Person person) {
// Validations
// Retreive from storage
return new Name("test");
}
},
address {
#Override
public void createAttribute(Person person) {
//Do some validations
//Save in some storage
}
#Override
public Address getAttribute(Person person) {
// Validations
// Retreive from storage
return new Name("test");
}
}
public abstract Object getAttribute(Person person);
public abstract void createAttribute(Person person);
}
Here the issue is that I would need to do typecasting to get the concrete object which is not recommended and I don't get any type of safety. How Should I go about so that using the enum value I can get my concrete object instead of the generic one.
Now I wanna call this as,
Arrays.stream(Attributes.values()).forEach(r -> {
r.createAttribute(person);
}
final Address address = Attributes.address.getAttribute(person);
final Name name = Attributes.name.getAttribute(person);
So now whenever I need to add a new attribute I don't want to write create methods for it in the Person class every time. I just add it to enum and it gets created. But now since I have the create method in the enum, I also want the getAttribute to be present here.
Here the issue is that I would need to do typecasting to get the concrete object which is not recommended and I don't get any type of safety.
You're right. Given an enum type E with an associated enum constant C, the type of the expression E.C is E. Java provides no mechanism for naming or representing a narrower type for that expression. One of the implications is that although an enum instance can implement methods with covariant return types, the covariance is not visible outside the instance. If you depend for some purpose on the narrower return type of one of those instances' methods, then casting is your only alternative.
And you're right that such casts are not type safe. They cannot be checked by the compiler, and in practice, you as programmer can get them wrong. But the information to perform a compile-time check is not expressed by the language, so there is no scope for a workaround in the language as it is defined today.
How Should I go about so that using the enum value I can get my concrete object instead of the generic one.
You should choose an altogether different approach, not involving an enum.
If you stuck with the enum then you would have to adopt an approach that relies on the enum instances to perform any tasks that depend on their own particular characteristics. Because you ask so persistently, one possibility would be to implement a variation on double dispatch. Instead of a getObject() method, you would have something like
void acceptReceiver(AttributeReceiver r, Person p);
paired with
public interface AttributeReceiver {
default void receiveName(Name name) { /* empty */ }
default void receiveAddress(Address addr) { /* empty */ }
}
Of course, the enum instances would have to implement acceptReceiver appropriately.
You would probably want to use that a little more directly than just to retrieve attributes, but you could use it to retrieve attributes something like this:
class Example {
Name name;
Address address;
void retrieveAttributes(Person person) {
AttributeReceiver receiver = new AttributeReceiver() {
public void receiveName(Name n) { name = n; }
public void receiveAddress(Address a) { addr = a; }
};
Attributes.name.acceptReceiver(receiver, person);
Attributes.address.acceptReceiver(receiver, person);
}
}
But that's awfully roundabout when you have the alternative of using (just) methods, whether on Person or even on some non-enum utility class. I continue not to see any advantage to involving an enum here. I think your code overall would be more complex and harder to understand and maintain with enums than without.
The root issue is that you are abstracting away details that you actually care about. That's a deep design flaw. You can program your way around it, but it would be better to choose a more appropriate level of abstraction in the first place.

Java - Alternatives to forcing subclass to have a static method

I often find I want to do something like this:
class Foo{
public static abstract String getParam();
}
To force a subclasses of Foo to return a parameter.
I know you can't do it and I know why you can't do it but the common alternative of:
class Foo{
public abstract String getParam();
}
Is unsatisfactory because it requires you to have an instance which is not helpful if you just want to know the value of the parameter and instantiating the class is expensive.
I'd be very interested to know of how people get around this without getting into using the "Constant Interface" anti pattern.
EDIT: I'll add some more detail about my specific problem, but this is just the current time when I've wanted to do something like this there are several others from the past.
My subclasses are all data processors and the superclass defines the common code between them which allows them to get the data, parse it and put it where it needs to go.
The processors each require certain parameters which are held in an SQL database. Each processor should be able to provide a list of parameters that it requires and the default values so the configuration database can be validated or initialised to defaults by checking the required parameters for each processor type.
Having it performed in the constructor of the processor is not acceptable because it only needs to be done once per class not once per object instance and should be done at system startup when an instance of each type of class may not yet be needed.
The best you can do here in a static context is something like one of the following:
a. Have a method you specifically look for, but is not part of any contract (and therefore you can't enforce anyone to implement) and look for that at runtime:
public static String getParam() { ... };
try {
Method m = clazz.getDeclaredMethod("getParam");
String param = (String) m.invoke(null);
}
catch (NoSuchMethodException e) {
// handle this error
}
b. Use an annotation, which suffers from the same issue in that you can't force people to put it on their classes.
#Target({TYPE})
#Retention(RUNTIME)
public #interface Param {
String value() default "";
}
#Param("foo")
public class MyClass { ... }
public static String getParam(Class<?> clazz) {
if (clazz.isAnnotationPresent(Param.class)) {
return clazz.getAnnotation(Param.class).value();
}
else {
// what to do if there is no annotation
}
}
I agree - I feel that this is a limitation of Java. Sure, they have made their case about the advantages of not allowing inherited static methods, so I get it, but the fact is I have run into cases where this would be useful. Consider this case:
I have a parent Condition class, and for each of its sub-classes, I want a getName() method that states the class' name. The name of the sub-class will not be the Java's class name, but will be some lower-case text string used for JSON purposes on a web front end. The getName() method will not change per instance, so it is safe to make it static. However, some of the sub-classes of the Condition class will not be allowed to have no-argument constructors - some of them I will need to require that some parameters are defined at instantiation.
I use the Reflections library to get all classes in a package at runtime. Now, I want a list of all the names of each Condition class that is in this package, so I can return it to a web front end for JavaScript parsing. I would go through the effort of just instantiating each class, but as I said, they do not all have no-argument constructors. I have designed the constructors of the sub-classes to throw an IllegalArgumentException if some of the parameters are not correctly defined, so I cannot merely pass in null arguments. This is why I want the getName() method to be static, but required for all sub-classes.
My current workaround is to do the following: In the Condition class (which is abstract), I have defined a method:
public String getName () {
throw new IllegalArugmentException ("Child class did not declare an overridden getName() method using a static getConditionName() method. This must be done in order for the class to be registerred with Condition.getAllConditions()");
}
So in each sub-class, I simply define:
#Override
public String getName () {
return getConditionName ();
}
And then I define a static getConditionName() method for each. This is not quite "forcing" each sub-class to do so, but I do it in a way where if getName() is ever inadvertently called, the programmer is instructed how to fix the problem.
It seems to me you want to solve the wrong problem with the wrong tool. If all subclasses define (can't really say inherit) your static method, you will still be unable to call it painlessly (To call the static method on a class not known at compile time would be via reflection or byte code manipulation).
And if the idea is to have a set of behaviors, why not just use instances that all implement the same interface? An instance with no specific state is cheap in terms of memory and construction time, and if there is no state you can always share one instance (flyweight pattern) for all callers.
If you just need to couple metadata with classes, you can build/use any metadata facility you like, the most basic (by hand) implementation is to use a Map where the class object is the key. If that suits your problem depends on your problem, which you don't really describe in detail.
EDIT: (Structural) Metadata would associate data with classes (thats only one flavor, but probably the more common one). Annotations can be used as very simple metadata facility (annotate the class with a parameter). There are countless other ways (and goals to achieve) to do it, on the complex side are frameworks that provide basically every bit of information designed into an UML model for access at runtime.
But what you describe (processors and parameters in database) is what I christened "set of behaviors". And the argument "parameters need to be loaded once per class" is moot, it completely ignores the idioms that can be used to solve this without needing anything 'static'. Namely, the flyweight pattern (for having only once instance) and lazy initialization (for doing work only once). Combine with factory as needed.
I'm having the same problem over and over again and it's hard for me to understand why Java 8 preferred to implement lambda instead of that.
Anyway, if your subclasses only implement retrieving a few parameters and doing rather simple tasks, you can use enumerations as they are very powerful in Java: you can basically consider it a fixed set of instances of an interface. They can have members, methods, etc. They just can't be instanciated (as they are "pre-instanciated").
public enum Processor {
PROC_IMAGE {
#Override
public String getParam() {
return "image";
}
},
PROC_TEXT {
#Override
public String getParam() {
return "text";
}
}
;
public abstract String getParam();
public boolean doProcessing() {
System.out.println(getParam());
}
}
The nice thing is that you can get all "instances" by calling Processor.values():
for (Processor p : Processorvalues()) {
System.out.println(String.format("Param %s: %s", p.name(), p.getParam()));
p.doProcessing();
}
If the processing is more complex, you can do it in other classes that are instanciated in the enum methods:
#Override
public String getParam() {
return new LookForParam("text").getParam();
}
You can then enrich the enumeration with any new processor you can think of.
The down side is that you can't use it if other people want to create new processors, as it means modifying the source file.
You can use the factory pattern to allow the system to create 'data' instances first, and create 'functional' instances later. The 'data' instances will contain the 'mandatory' getters that you wanted to have static. The 'functional' instances do complex parameter validation and/or expensive construction. Of course the parameter setter in the factory can also so preliminary validation.
public abstract class Processor { /*...*/ }
public interface ProcessorFactory {
String getName(); // The mandatory getter in this example
void setParameter(String parameter, String value);
/** #throws IllegalStateException when parameter validation fails */
Processor construct();
}
public class ProcessorA implements ProcessorFactory {
#Override
public String getName() { return "processor-a"; }
#Override
public void setParameter(String parameter, String value) {
Objects.requireNonNull(parameter, "parameter");
Objects.requireNonNull(value, "value");
switch (parameter) {
case "source": setSource(value); break;
/*...*/
default: throw new IllegalArgumentException("Unknown parameter: " + parameter);
}
}
private void setSource(String value) { /*...*/ }
#Override
public Processor construct() {
return new ProcessorAImpl();
}
// Doesn't have to be an inner class. It's up to you.
private class ProcessorAImpl extends Processor { /*...*/ }
}

Java - Factory Method that returns generic Base type

I'm trying to genericize a factory method that returns
a generic Base class. It works, but I'm getting the
"BaseClass is a raw type..." warning.
I've read through the Java docs on Generic methods,
but I'm still not quite getting how to accomplish this.
Here's some code:
Class #1
//base abstract class
public abstract class BaseFormatter<T>
{
public abstract String formatValue(T value);
}
Class #2
//two implementations of concrete classes
public class FooFormatter extends BaseFormatter<Integer>
{
#Override
public String formatValue(Integer value)
{
//return a formatted String
}
}
Class #3
public class BarFormatter extends BaseFormatter<String>
{
#Override
public String formatValue(String value)
{
//return a formatted String
}
}
Factory Method in a separate class
public static BaseFormatter getFormatter(Integer unrelatedInteger)
{
if (FOO_FORMATTER.equals(unrelatedInteger))
return new FooFormatter();
else if (BAR_FORMATTER.equals(unrelatedInteger))
return new BarFormatter();
//else...
}
Call to the Factory Method from elsewhere in the code
BaseFormatter<Integer> formatter = getFormatter(someInteger);
formatter.formatValue(myIntegerToFormat);
The problem is the getFormatter() method warns that BaseFormatter is
a raw type, which it is. I've tried various things like BaseFormatter
et al. I, of course, want the return type to be generic, as in the declared
BaseFormatter in the calling method.
Note that the formatter type is not based on class type. e.g. not all Integer
values are formatted with a FooFormatter. There are two or three different
ways an Integer (or String, or List) can be formatted. That's what the
param unrelatedInteger is for.
Thanks in advance for any feedback.
If getFormatter is defined in BaseFormatter, then use:
public static BaseFormatter<T> getFormatter(Integer unrelatedInteger)
If getFormatter is defined in another class than BaseFormatter, then use:
public static BaseFormatter<?> getFormatter(Integer unrelatedInteger)
You're actuaaly saying that there's no connection between the typed parameter of BaseFormatter and the unrelatedInteger that is passed as argument to the getFormatter method.
I get some other warning:
Uncehcked Assignment: BaseFormatter to BaseFormatter<Integer>
This warning is worse than the one you indicated. It warns that this user code might try to insert a BaseFormatter<String> into BaseFormatter<Integer>, something that will be noticed only when fails in runtime... Consider a user accidentally uses you factory method like such:
BaseFormatter<Integer> myUnsafeFormatter =
FormatterFactory.getFormatter(unrelatedIntegerForBarFormatter);
The compiler cannot relate the unrelatedInteger with the parameterized type of the returned BaseFormatter.
Alternitavely, I'd let the user explicitly use the concrete formatter constructors. Any common code shared by all formatters could be put into FormatterUtils class (just don't let that utils class to grow to much...).
Some type systems in academic languages can express a so-called dependent sum. Java certainly cannot; so what, sensibly, could be the type of the object returned by the getFormatter method? The best we can do is BaseFormatter< ? extends Object >, or BaseFormatter< ? > for short, as Integer and String have only Object in common.
I think the original post begs the question, why must we use an integer to decide what formatter to return, and if the type of formatter would not be known by the caller, why would the caller need a stronger variable type than BaseFormatter< ? >?

Type-safe method reflection in Java

Is any practical way to reference a method on a class in a type-safe manner? A basic example is if I wanted to create something like the following utility function:
public Result validateField(Object data, String fieldName,
ValidationOptions options) { ... }
In order to call it, I would have to do:
validateField(data, "phoneNumber", options);
Which forces me to either use a magic string, or declare a constant somewhere with that string.
I'm pretty sure there's no way to get around that with the stock Java language, but is there some kind of (production grade) pre-compiler or alternative compiler that may offer a work around? (similar to how AspectJ extends the Java language) It would be nice to do something like the following instead:
public Result validateField(Object data, Method method,
ValidationOptions options) { ... }
And call it with:
validateField(data, Person.phoneNumber.getter, options);
As others mention, there is no real way to do this... and I've not seen a precompiler that supports it. The syntax would be interesting, to say the least. Even in your example, it could only cover a small subset of the potential reflective possibilities that a user might want to do since it won't handle non-standard accessors or methods that take arguments, etc..
Even if it's impossible to check at compile time, if you want bad code to fail as soon as possible then one approach is to resolve referenced Method objects at class initialization time.
Imagine you have a utility method for looking up Method objects that maybe throws error or runtime exception:
public static Method lookupMethod( Class c, String name, Class... args ) {
// do the lookup or throw an unchecked exception of some kind with a really
// good error message
}
Then in your classes, have constants to preresolve the methods you will use:
public class MyClass {
private static final Method GET_PHONE_NUM = MyUtils.lookupMethod( PhoneNumber.class, "getPhoneNumber" );
....
public void someMethod() {
validateField(data, GET_PHONE_NUM, options);
}
}
At least then it will fail as soon as MyClass is loaded the first time.
I use reflection a lot, especially bean property reflection and I've just gotten used to late exceptions at runtime. But that style of bean code tends to error late for all kinds of other reasons, being very dynamic and all. For something in between, the above would help.
There isn't anything in the language yet - but part of the closures proposal for Java 7 includes method literals, I believe.
I don't have any suggestions beyond that, I'm afraid.
Check out https://proxetta.jodd.org/refs/methref. It uses the Jodd proxy library (Proxetta) to proxy your type. Not sure about its performance characteristics, but it does provide type safety.
An example: Suppose Str.class has method .boo(), and you want to get its name as the string "boo":
String methodName = Methref.of(Str.class).name(Str::boo);
There's more to the API than the example above: https://oblac.github.io/jodd-site/javadoc/jodd/methref/Methref.html
Is any practical way to reference a method on a class in a type-safe manner?
First of all, reflection is type-safe. It is just that it is dynamically typed, not statically typed.
So, assuming that you want a statically typed equivalent of reflection, the theoretical answer is that it is impossible. Consider this:
Method m;
if (arbitraryFunction(obj)) {
m = obj.getClass().getDeclaredMethod("foo", ...);
} else {
m = obj.getClass().getDeclaredMethod("bar", ...);
}
Can we do this so that that runtime type exceptions cannot happen? In general NO, since this would entail proving that arbitraryFunction(obj) terminates. (This is equivalent to the Halting Problem, which is proven to be unsolvable in general, and is intractable using state-of-the-art theorem proving technology ... AFAIK.)
And I think that this road-block would apply to any approach where you could inject arbitrary Java code into the logic that is used to reflectively select a method from an object's class.
To my mind, the only moderately practical approach at the moment would be to replace the reflective code with something that generates and compiles Java source code. If this process occurs before you "run" the application, you've satisfied the requirement for static type-safety.
I was more asking about reflection in which the result is always the same. I.E. Person.class.getMethod("getPhoneNumber", null) would always return the same method and it's entirely possible to resolve it at compile time.
What happens if after compiling the class containing this code, you change Person to remove the getPhoneNumber method?
The only way you can be sure that you can resolve getPhoneNumber reflectively is if you can somehow prevent Person from being changed. But you can't do that in Java. Runtime binding of classes is a fundamental part of the language.
(For record, if you did that for a method that you called non-reflectively, you would get an IncompatibleClassChangeError of some kind when the two classes were loaded ...)
It has been pointed out that in Java 8 and later you could declare your validator something like this:
public Result validateField(Object data,
SomeFunctionalInterface function,
ValidationOptions options) { ... }
where SomeFunctionalInterface corresponds to the (loosely speaking) common signature of the methods you are validating.
Then you can call it with a method reference; e.g.
validateField(data, SomeClass::someMethod, options)
This is approach is statically type-safe. You will get a compilation error if SomeClass doesn't have someMethod or if it doesn't conform to SomeFunctionalInterface.
But you can't use a string to denote the method name. Looking up a method by name would entail either reflection ... or something else that side-steps static (i.e. compile time / load time) type safety.
Java misses the syntax sugar to do something as nice as Person.phoneNumber.getter. But if Person is an interface, you could record the getter method using a dynamic proxy. You could record methods on non-final classes as well using CGLib, the same way Mockito does it.
MethodSelector<Person> selector = new MethodSelector<Person>(Person.class);
selector.select().getPhoneNumber();
validateField(data, selector.getMethod(), options);
Code for MethodSelector: https://gist.github.com/stijnvanbael/5965609
Inspired by mocking frameworks, we could dream up the following syntax:
validator.validateField(data, options).getPhoneNumber();
Result validationResult = validator.getResult();
The trick is the generic declaration:
class Validator {
public <T> T validateField(T data, options) {...}
}
Now the return type of the method is the same as your data object's type and you can use code completion (and static checking) to access all the methods, including the getter methods.
As a downside, the code isn't quite intuitive to read, since the call to the getter doesn't actually get anything, but instead instructs the validator to validate the field.
Another possible option would be to annotate the fields in your data class:
class FooData {
#Validate(new ValidationOptions(...))
private PhoneNumber phoneNumber;
}
And then just call:
FooData data;
validator.validate(data);
to validate all fields according to the annotated options.
The framework picklock lets you do the following:
class Data {
private PhoneNumber phoneNumber;
}
interface OpenData {
PhoneNumber getPhoneNumber(); //is mapped to the field phoneNumber
}
Object data = new Data();
PhoneNumber number = ObjectAccess
.unlock(data)
.features(OpenData.class)
.getPhoneNumber();
This works in a similar way setters and private methods. Of course, this is only a wrapper for reflection, but the exception does not occur at unlocking time not at call time. If you need it at build time, you could write a unit test with:
assertThat(Data.class, providesFeaturesOf(OpenData.class));
I found a way to get the Method instance using Lambdas. It works only on interface methods though currently.
It works using net.jodah:typetools which is a very lightweight library.
https://github.com/jhalterman/typetools
public final class MethodResolver {
private interface Invocable<I> {
void invokeWithParams(I instance, Class<?>[] parameterTypes) throws Throwable;
}
interface ZeroParameters<I, R> extends Invocable<I> {
R invoke(I instance) throws Throwable;
#Override
default void invokeWithParams(I instance, Class<?>[] parameterTypes) throws Throwable {
invoke(instance);
}
}
public static <I, R> Method toMethod0(ZeroParameters<I, R> call) {
return toMethod(ZeroParameters.class, call, 1);
}
interface OneParameters<I, P1, R> extends Invocable<I> {
R invoke(I instance, P1 p1) throws Throwable;
#Override
default void invokeWithParams(I instance, Class<?>[] parameterTypes) throws Throwable {
invoke(instance, param(parameterTypes[1]));
}
}
public static <I, P1, R> Method toMethod1(OneParameters<I, P1, R> call) {
return toMethod(OneParameters.class, call, 2);
}
interface TwoParameters<I, P1, P2, R> extends Invocable<I> {
R invoke(I instance, P1 p1, P2 p2) throws Throwable;
#Override
default void invokeWithParams(I instance, Class<?>[] parameterTypes) throws Throwable {
invoke(instance, param(parameterTypes[1]), param(parameterTypes[2]));
}
}
public static <I, P1, P2, R> Method toMethod2(TwoParameters<I, P1, P2, R> call) {
return toMethod(TwoParameters.class, call, 3);
}
private static final Map<Class<?>, Object> parameterMap = new HashMap<>();
static {
parameterMap.put(Boolean.class, false);
parameterMap.put(Byte.class, (byte) 0);
parameterMap.put(Short.class, (short) 0);
parameterMap.put(Integer.class, 0);
parameterMap.put(Long.class, (long) 0);
parameterMap.put(Float.class, (float) 0);
parameterMap.put(Double.class, (double) 0);
}
#SuppressWarnings("unchecked")
private static <T> T param(Class<?> type) {
return (T) parameterMap.get(type);
}
private static <I> Method toMethod(Class<?> callType, Invocable<I> call, int responseTypeIndex) {
Class<?>[] typeData = TypeResolver.resolveRawArguments(callType, call.getClass());
Class<?> instanceClass = typeData[0];
Class<?> responseType = responseTypeIndex != -1 ? typeData[responseTypeIndex] : Void.class;
AtomicReference<Method> ref = new AtomicReference<>();
I instance = createProxy(instanceClass, responseType, ref);
try {
call.invokeWithParams(instance, typeData);
} catch (final Throwable e) {
throw new IllegalStateException("Failed to call no-op proxy", e);
}
return ref.get();
}
#SuppressWarnings("unchecked")
private static <I> I createProxy(Class<?> instanceClass, Class<?> responseType,
AtomicReference<Method> ref) {
return (I) Proxy.newProxyInstance(MethodResolver.class.getClassLoader(),
new Class[] {instanceClass},
(proxy, method, args) -> {
ref.set(method);
return parameterMap.get(responseType);
});
}
}
Usage:
Method method = MethodResolver.toMethod2(SomeIFace::foobar);
System.out.println(method); // public abstract example.Result example.SomeIFace.foobar(java.lang.String,boolean)
Method get = MethodResolver.<Supplier, Object>toMethod0(Supplier::get);
System.out.println(get); // public abstract java.lang.Object java.util.function.Supplier.get()
Method accept = MethodResolver.<IntFunction, Integer, Object>toMethod1(IntFunction::apply);
System.out.println(accept); // public abstract java.lang.Object java.util.function.IntFunction.apply(int)
Method apply = MethodResolver.<BiFunction, Object, Object, Object>toMethod2(BiFunction::apply);
System.out.println(apply); // public abstract java.lang.Object java.util.function.BiFunction.apply(java.lang.Object,java.lang.Object)
Unfortunately you have to create a new interface and method based on the parameter count and whether the method returns void or not.
However, if you have a somewhat fixed/limited method signature/parameter types, then this becomes quite handy.

Categories