Method as parameter with signature contract? - java

I would like to know how to create a contract with the caller for the Method parameter in the event the method has parameters itself. So that I use...
ClassA {
String string_ = "HI";
public static void subscribe(Object class, Method action) {
action.invoke(class, string_);
}
}
ClassB {
ClassB() {
ClassA.subscribe(this, this.getClass().getMethod("load", String.class));
}
public void load(String input) {
if(input.equals("HI")) {
...
}
}
}
I would like to know how to ensure the Method passed as "action" takes String as a parameter (i.e. ensure Method action == load(String){})? Is there something like this available:
public static void subscribe(Object class, Method action(String.class)) {
I want to do it in the method signature of subscribe so that it is obvious to the calling class (ClassB) that it needs to be prepared to take an argument of specified type.
EDIT: Updated last code bit so not to appear as if Method was generic. Poor choice of using <> on my part to represent an example of what I was trying to convey.

There's no way to do that in Java. The Method class is not generic, and there is no way for it to be so, because methods can take any number of parameters, and there is no way to make a class generic over a variable number of types.
Probably the best you can do is to declare your own type to use instead of Method:
public interface Action<T, P> {
public void invoke(T target, P parameter);
}
Then:
public static <T> void subscribe(T obj, Action<T, String> action) {
action.invoke(obj, string_);
}
ClassB() {
ClassA.subscribe(this, new Action<ClassB, String>() {
public void invoke(ClassB target, String parameter) {
target.load(parameter);
}
});
}

In C# there are means to achieve what you are trying to do but I can't think of a way to ensure that at compile time for java.
can you resort to using intefaces?
interface ILoader{
void load(String input);
}
ClassA {
String string_ = "HI";
public static void subscribe(ILoader loader) {
loader.load( string_);
}
}
ClassB implements ILoader {
ClassB() {
ClassA.subscribe(this);
}
public void load(String input) {
if(input.equals("HI")) {
...
}
}
}

Couldn't you use a slight modification of the Command Pattern?
puclic interface LoadCommand {
public load(String input);
}
public class ClassB implements LoadCommand {
public load(String input) {
// do stuff here
}
}
public class ClassA {
String myInput = "HI";
public static void subscribe(LoadCommand command) {
command.load(myInput)
}
}
The load method in the LoadCommand interface takes one String argument.

Related

How Can I Create method In Java With Same Type Parameter?

My code looks like below:
enum EnumType {
CATEGORY,
GROUP,
MAIN
}
Methods:
public void call(EnumType type){
switch(type):
case CATEGORY:
return methodForCategory();
case GROUP:
return methodForGroup();
...
}
public void methodForCategory(){
... Operations according to EnumType.CATEGORY
}
public void methodForGroup(){
... Operations according to EnumType.GROUP
}
public void methodForMain(){
... Operations according to EnumType.MAIN
}
But I want to call it without switch/case like below;
public void call(EnumType type){
methodForType(EnumType type);
}
Is it possible or is there any better alternative?
You can create the method implementation inside the enum as below:
public enum EnumType {
CATEGORY {
#Override
public void processMethod() {
// Do something here
}
},
GROUP {
#Override
public void processMethod() {
// Do something here
}
},
MAIN {
#Override
public void processMethod() {
// Do something here
}
};
public abstract void processMethod();
}
And update call method implementation as:
public void call(EnumType type){
type.processMethod();
}
And switch code should not return anything as method return type is void.
You can use an EnumMap as a registry of methods and using the Enum supplied you can return the correct implementation of the Runnable. I have used Runnable as a functional interface as it takes no inputs and produces no output.
In another class where you have the business logic, you can initialize the map and add the corresponding Runnable implementation:
class Strategy{
private final EnumMap<EnumType, Runnable> map;
public Strategy(){
//Initialize values here
map = new EnumMap<>(EnumType.class);
map.put(EnumType.CATEGORY, () -> {
System.out.println("CATEGORY");
});
map.put(EnumType.GROUP, () -> {
System.out.println("GROUP");
});
map.put(EnumType.MAIN, () -> {
System.out.println("MAIN");
});
}
public void call(EnumType type){
map.get(type).run();
}
}
Then you can invoke the call() method by supplying the type of Enum as a parameter:
public static void main(String args[]){
Strategy str = new Strategy();
str.call(EnumType.CATEGORY);
str.call(EnumType.GROUP);
str.call(EnumType.MAIN);
}

Generic Method with object as argument in Java

There are two classes A and B which have similar methods. How to write a generic method that takes either one of the class object as argument and will be able to call the methods of that class.
Edit : I do not have control over class A, B. I get them only as arguments. So i cannot modify add them.
public class methods {
public static void main(String[] args) {
new methods().getName(new B());
new methods().getName(new A());
}
private <T> void getName(T obj){
// obj.getName()
}
}
class A {
String name = "ClassA";
public void getName(){
System.out.println(name);
}
}
class B {
String name = "ClassB";
public void getName(){
System.out.println(name);
}
}
If the two classes do not implement a common interface, you could use reflection, but this is not type safe (you won't get any compilation errors if A or B no longer support getName() and reflection is much slower than calling a method directly.
You could also implement two adapters that share an interface and use those (with generics):
interface Wrapper {
String getName();
}
class WrapperA implements Wrapper {
final private A a;
public WrapperA(A wrapped) {
this.a = wrapped;
}
#Override public String getName() {
return a.getName();
}
}
Below solution uses instanceof operator in the generic method to reach your output.
public static void main(String[] args){
new methods().getName(new B());
new methods().getName(new A());
}
private <T> void getName(T obj) {
if(obj instanceof B){
((B) obj).getName();
}
else{
((A) obj).getName();
}
}

How to modify/decorator an object returned from 3rd party API using javassist/CGLib

I have an 3rd party API call which returns the following object:
public class A {
protected void common() {
System.out.println("common is called in A");
}
public void test1() {
common();
System.out.println("test1 is called in A");
}
public void test2() {
common();
System.out.println("test2 is called in A");
}
}
But I'd like to modify its behavior like the following ModifiedA shows:
public class ModifiedA extends A {
#Override
protected void common() {
super.common();
System.out.println("common is called in ModifiedA");
}
}
So what I am trying to do is:
A a = 3rdPartyAPI_call();
//
// Now I'd like to get a ModifiedA which has changed common() behavior.
//
How to use javassist/CGLIB to accomplish this ?
One easy way may be to like this:
public class ModifiedA extends A {
private A a;
public ModifiedA(final A a) {
this.a = a;
}
//
// Override every public method in A
//
#Override
protected void common() {
super.common();
System.out.println("common is called in ModifiedA");
}
}
But since A's definition comes from 3rd party and is very complex and may change, so I'd like to use a proxy to do this?
Thanks for your comments in adavance.
You can use CGLib to implement a delegator pattern without having to override all the methods. There are a few different approaches to implement this depending on style but here is one similar to your example.
You can wrap the instance using a cglib Enhancer:
public static <T> T wrapInstance(final T original) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(original.getClass());
enhancer.setCallback(new MethodInterceptor() {
#Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
Object returnValue = proxy.invoke(original, args);
if (method.getName().equals("common")) {
System.out.println("common is called");
}
return returnValue;
}
});
return (T) enhancer.create();
}
eclps post will fullfill your requirement and it works.I want to add some more code to eclps code.
Adding filter which give index zero for common method and rest all method to One. MethodInterceptor callback will intercept only common method and rest all method use NoOp intercetor(which will call super class apis).This way filtering is not happening for every method call.
public static <T> T wrapInstance(final T original) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(original.getClass());
enhancer.setCallbackFilter(new CallbackFilter() {
#Override
public int accept(Method method) {
if (method.getName().equals("common")) {
return 0;
}
return 1;
}
});
enhancer.setCallbacks(new Callback[]{new MethodInterceptor() {
#Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// only common method will intercept this call back.
return proxy.invoke(this, args);
}
}, NoOp.INSTANCE});
return (T) enhancer.create();
}

How would I overload method in an interface?

if I have this interface
public interface someInterface {
// method 1
public String getValue(String arg1);
// method 2
public String getValue(String arg1, String arg2);
}
I want to be able to pass in 1 or 2 string to the getValue method without having to override both in each implementing class.
public class SomeClass1 impelments someInterface
{
#Override
public String getValue(String arg1);
}
public class SomeClass2 implements someInterface
{
#Override
public String getValue(String arg1, String arg2);
}
this won't work because SomeClass1 needs to implement method 2 and SomeClass2 needs to implement method 1.
Am I stuck doing this?
public interface someInterface2 {
public String getValue(String... args);
}
public class SomeClass3 implements someInterface2
{
#Override
public String getValue(String... args) {
if (args.length != 1) {
throw IllegalArgumentException();
}
// code
}
}
public class SomeClass4 implements someInterface2
{
#Override
public String getValue(String... args) {
if (args.length != 2) {
throw IllegalArgumentException();
}
// code
}
}
someInterface2 someClass3 = new SomeClass3();
someInterface2 someClass4 = new SomeClass4();
String test1 = someClass3.getValue("String 1");
String test2 = someClass4.getValue("String 1, "String 2");
Is there a better way of doing this?
An interface serves as a contract for the users of that interface: you specify what methods are available (in all implementations) and how they are called. If two implementations of an interface need a different method, then that method should not be part of the interface:
public interface Lookup {
}
public class MapLookup implements Lookup {
public String getValue(String key) {
//...
}
}
public class GuavaLookup implements Lookup {
public String getValue(String row, String column) {
// ...
}
}
In your program, you will know which implementation you use, so you can simply call the right function:
public class Program {
private Lookup lookup = new MapLookup();
public void printLookup(String key) {
// I hardcoded lookup to be of type MapLookup, so I can cast:
System.out.println(((MapLookup)lookup).getValue(key));
}
}
Alternative approach
If your class Program is more generic and uses dependency injections, you may not know which implementation you have. Then, I would make a new interface Key, which can be either type of key:
public interface Lookup {
// ...
public String getValue(Key key);
}
public interface Key {
}
public MapKey implements Key {
private String key;
// ...
}
public GuavaKey implements Key {
private String row, column;
// ...
}
The dependency injection in your program might come from some factory implementation. Since you cannot know which type of lookup you use, you need a single contract for getValue.
public interface Factory {
public Lookup getLookup();
public Key getKey();
}
public class Program {
private Lookup lookup;
public Program(Factory factory) {
lookup = factory.getLookup();
}
public void printLookup(Factory factory) {
System.out.println((lookup.getValue(factory.getKey()));
}
}
As of Java 8, you can have an interface provide an implementation of a method, through the use of the default keyword. Therefore a new solution would be to provide a default implementation of both methods which maybe throws an exception, then derive the actual implementation from the default interface.
Anyways here is how you can do this:
public interface SomeInterface {
// method 1
default String getValue(String arg1) {
// you decide what happens with this default implementation
}
// method 2
default String getValue(String arg1, String arg2) {
// you decide what happens with this default implementation
}
}
Finally, make the classes override the correct methods
public class SomeClass1 implements SomeInterface {
#Override
public String getValue(String arg1) {
return arg1;
}
}
public class SomeClass2 implements SomeInterface {
#Override
public String getValue(String arg1, String arg2) {
return arg1 + " " + arg2;
}
}
A solution (not very elegant) might look loke this:
public abstract class SomeClass {
public String getValue(String arg1) {
throw new IllegalArgumentException();
}
public String getValue(String arg1, String arg2) {
throw new IllegalArgumentException();
}
}
public class SomeClass1 extends SomeClass {
public String getValue(String arg1) {
// return sth
}
}
public class SomeClass2 extends SomeClass {
public String getValue(String arg1, String arg2) {
// return sth
}
}
However there's a drawback - SomeClass1 and SomeClass2 can't inherit directly other class.
If the second value can be considered optional in a sense and you always have the 2 arguments when calling you could create a wrapper class which implements the 2 parameter interface passing the 1 parameter implementation as a constructor parameter and calling that in the method, e.g. something like this:
interface A{
method1(P1)
}
interface B{
method2(P1, P2)
}
class Wrap implements B{
Wrap(A impl)
override method2(P1, P2){
call impl.method1(P1)
}
}
public interface SomeInterface {
default void print(String s) {
System.out.println(s);
}
}
public class SomeClass implements SomeInterface {
/**
* Note the this overloads {#link SomeInterface#print(String)},
* not overrides it!
*/
public void print(int i) {
System.out.println(i);
}
}

Is it possible to have an enum that contains constructors for objects?

I'm testing out a different sort of pattern. I've already got the code working in a switch statement, but I'd like to try something a little more ecclectic... for research purposes.
Say I have 4 classes, Class1, Class2, Class3, and Class4 that all extend BaseClass. I want to put them into an enum, like so:
enum ClassFactories {
Class1(Class1.class),
Class2(Class2.class),
Class3(Class3.class),
Class4(Class4.class);
private final Class factory;
ClassFactories(Class factory) {
this.factory = factory;
}
public BaseClass generate() {
BaseClass b = null;
try {
b = (BaseClass)this.factory.newInstance();
} catch (Exception e) {
// handle any exceptions
}
return f;
}
}
In a factory method that is passed an int, I want to be able to do something like this:
public void fakeMethod(int type) {
BaseClass someClass = ClassFactories.values()[type].generate();
someClass.doStuff();
}
Is there a cleaner/easier way of doing this? I'm not so much concerned with readability (right now), I'm just curious if this is possible.
Yes, this is possible. Something like a 'Template Method' approach. So for example
public enum ClassFactory {
Class1() {
#Override public void generate() {
System.out.println("I'm in Class 1.");
}
},
Class2() {
#Override public void generate() {
System.out.println("I'm in Class 2.");
}
};
//template method
public abstract void generate();
private static final Map<Integer, ClassFactory > lookup
= new HashMap<Integer, ClassFactory >();
static {
for (ClassFactory s : EnumSet.allOf(ClassFactory.class))
lookup.put(s.getIntValue(), s);
}
public static ClassFactory getValue(int intValue) {
return lookup.get(intValue);
}
}
INVOCATION CODE
With the use of static imports, the client code calling this enumeration would look like:
Class1.generate();
Class2.generate();
//or better...
getClass().generate();
Or
public void fakeMethod(int type) {
ClassFactory.getValue(type).generate();
}

Categories

Resources