I have this (simplified) java interface
public interface MyInterface<T> {
public String run( T arg );
}
and some classes that implement that interface, i.e.
public final class SomeImplementation1 implements MyInterface<String> {
#Override
public String run( String arg) {
// do something with arg and return a string
}
}
and
public final class SomeImplementation2 implements MyInterface<CustomClass> {
#Override
public String run( CustomClass arg) {
// do something with arg and return a string
}
}
Now, I have a global resource manager for all of those implementations, which instantiates all of them in a List for latter usage. What I would like to achieve is something like this, which obviously gives me an error
public final class MyInterfaceManager {
private List<MyInterface<?>> elements = new List<MyInterface<?>>();
public MyInterfaceManager() {
elements.put( new SomeImplementation1() );
elements.put( new SomeImplementation2() );
// more implementations added
}
// this is what I would like to achieve
public <T> void run( T arg ) {
for( MyInterface<?> element: elements ) {
String res = element.run( arg ); // ERROR
}
}
}
because "arg cannot be converted to capture#1 of ? by method invocation conversion".
A possible solution could be to perform an instanceof test inside the loop, and cast the element to its real type, along with the argument as well, like that
public <T> void run( T arg ) {
for( MyInterface<T> element: elements ) {
if (element instanceof SomeImplementation2) {
String res = ((SomeImplementation2)element).run( (CustomClass)arg );
} else if // other tests here ...
}
}
But i don't like it, it's not elegant at all, and it forces me to do lots of instanceof and casts.
So, I'm wondering if there is a better way to achieve this.
Thanks for your help :)
You are running into type erasure. You need to add another method to the interface that returns the Class instance that relates to the type parameter <T>, this will allow you to do runtime checks on that Class.
I would accomplish this thus:
public interface MyInterface<T> {
String run( T arg );
Class<T> type();
}
So the interface returns its type. N.B. all interface members are public by default - no need for the extra public.
public final class SomeImplementation1 implements MyInterface<String> {
#Override
public String run(final String arg) {
return arg;
}
#Override
public Class<String> type() {
return String.class;
}
}
#SuppressWarnings({"unchecked"})
public static <T> String run(final T arg) {
for (final MyInterface<?> element : elements) {
if (element.type().isAssignableFrom(arg.getClass())) {
return ((MyInterface<T>) element).run(arg);
}
}
throw new IllegalArgumentException("No element found.");
}
The logic is that for each MyInterface you check whether the argument provided is safely castable to that MyInterface's type(). If it is then you can cast the whole MyInterface to the arg's type. This is unchecked as the compiler cannot verify this as compile time, but as you are manually doing a check this warning can be ignored.
public static void main(String[] args) throws Exception {
elements = new LinkedList<>();
elements.add(new SomeImplementation1());
System.out.println(run("test"));
System.out.println(run(1));
}
Output:
test
Exception in thread "main" java.lang.IllegalArgumentException: No element found.
at com.XXX.App.run(App.java:33)
at com.XXX.App.main(App.java:55)
As expected.
Related
I need to get Class< ? extends List < AlarmRule > > instance.
This is my code:
public static BoundedMatcher<Object, List<AlarmRule>> setBind() {
Class<? extends List<AlarmRule>> clazz = null; // I need to give clazz a value,but i don't know how.
return new BoundedMatcher<Object, List<AlarmRule>>(clazz) {
#Override
public void describeTo(Description description) {
description.appendText("with item content: ");
}
#Override
protected boolean matchesSafely(List<AlarmRule> list) {
return list.stream().anyMatch(alarmRule -> test_reminder_corn.equals(alarmRule.cron));
}
};
}
Thanks for any help!
write like this
public static BoundedMatcher<Object, List> setBind() {
return new BoundedMatcher<Object, List>(List.class) {
#Override
public void describeTo(Description description) {
description.appendText("with item content: ");
}
#Override
protected boolean matchesSafely(List list) {
// convert every object in list to AlarmRule
return false;
}
};
}
In your case you need to pass List.class in the constructor.
However, because of java type erasure, any List may be passed to your matcher so you need to add additional code to ensure your list actually contains AlarmRule objects or you will get a ClassCastException at runtime.
This question already has answers here:
Verify that all getter methods are called
(2 answers)
Closed 6 years ago.
Lets say I have an interface that has many (like 30) getter like methods.
I would like to validate all the methods gets called with out specifying each and every method (that way if the interface gets update we have a failure).
For now I will just write a plain Java proxy handler but I was curious if there was a way to do this in Mockito.
I ended up just using a Proxy. I figured I would post it for others.
It is not elegant but it works.
One could add additional validate methods like sub or super set validation of methods instead of an exact match.
#Test
public void test() {
VerifyAllMethods h = new VerifyAllMethods() {
#Override
public Object runMethod(Method method, Object[] args) throws Throwable {
Class<?> rt = method.getReturnType();
if (Optional.class.equals(rt)) {
return Optional.absent();
}
else if (String.class.equals(rt)) {
return "mock";
}
else if (Integer.class.equals(rt)) {
return 1;
}
else if (List.class.equals(rt)) {
return Lists.newArrayList("1");
}
else {
return rt.newInstance();
}
}
};
SomeInterface mf = h.mock(SomeInterface.class);
// do something with SomeInterface
h.validateEquals(SomeInterface.class);
}
public abstract static class VerifyAllMethods implements InvocationHandler {
private final Set<Method> actualMethods = Sets.newLinkedHashSet();
public VerifyAllMethods() {
}
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
actualMethods.add(method);
return runMethod(method, args);
}
public abstract Object runMethod(Method method, Object[] args) throws Throwable;
public Set<Method> getActualMethods() {
return actualMethods;
}
public void validateEquals(Class<?> iface) {
Set<Method> methods = Sets.newHashSet(iface.getMethods());
/*
* Asserting Equals on strings is better for IDE as
* most generate a diff.
*/
assertEquals(methodsToString(methods), methodsToString(actualMethods));
}
public String methodsToString(Iterable<Method> methods) {
List<String> names = Lists.newArrayList();
for (Method m : methods) {
names.add(m.toString());
}
Collections.sort(names);
return Joiner.on("\n").join(names);
}
#SuppressWarnings("unchecked")
public <T> T mock(Class<T> iface) {
actualMethods.clear();
Class<?>[] interfaces = {iface};
return (T) Proxy.newProxyInstance(getClass().getClassLoader(), interfaces , this);
}
}
I have an third-party RPC-API that provides an interface similar to that of java.sql.ResultSet (for reading values) and java.sql.PreparedStatement (for writing values). Assume it looks something like this:
public interface RemoteDeviceProxy {
public void setBoolean(Boolean value);
public void setInteger(Integer value);
// ...
public Boolean getBoolean();
public Integer getInteger();
// ...
}
I want to write a wrapper for this API that uses generics to create instances of specific types:
public class <T> RemoteVariable {
private final RemoteDeviceProxy wrappedDevice;
public RemoteVariable(RemoteDeviceProxy wrappedDevice) {
this.wrappedDevice = wrappedDevice;
}
public T get() {
// should call wrappedDevice.getBoolean() if T is Boolean, etc.
// how to implement?
}
public void set(T newValue) {
// should call wrappedDevice.setBoolean(newValue) if T is Boolean, etc.
// implement using instanceof
}
}
How can I implement the getter in my generic wrapper? I have found this answer which explains a similar scenario in depth, but I am not able to transfer this to my problem. Specifically, when I write this:
public T get() {
Type[] actualTypeArguments = ((ParameterizedType) getClass())
.getActualTypeArguments();
}
I get a compiler error saying I cannot cast to ParameterizedType, and I do not understand why. Can anyone explain how to achieve this?
Here is one way:
public class <T> RemoteVariable {
private final RemoteDeviceProxy wrappedDevice;
private final Class<T> clazz;
public RemoteVariable(RemoteDeviceProxy wrappedDevice, Class<T> clazz) {
this.wrappedDevice = wrappedDevice;
this.clazz = clazz;
}
public T get() {
if(clazz == Boolean.class){return clazz.cast(wrappedDevice.getBoolean());}
else if(clazz == Integer.class){return clazz.cast(wrappedDevice.getInteger());}
// ...
}
// ...
}
I thought over this quite a while and finally came up with a different approach:
First I added a getter to you RemoteVariable class:
protected RemoteDeviceProxy getWrappedProxy() {
return wrappedProxy;
}
Second I created a builder interface that will be used by a factory later:
public interface RemoteVariableBuilder {
public <T> RemoteVariable<T> buildNewVariable(RemoteDeviceProxy wrappedProxy);
}
Then I created non generic sub classes for Boolean...
public class RemoteBooleanVariable extends RemoteVariable<Boolean> implements RemoteVariableBuilder {
public RemoteBooleanVariable(RemoteDeviceProxy wrappedProxy) {
super(wrappedProxy);
}
#SuppressWarnings("unchecked")
#Override
public <T> RemoteVariable<T> buildNewVariable(RemoteDeviceProxy wrappedProxy) {
return (RemoteVariable<T>) new RemoteBooleanVariable(wrappedProxy);
}
#Override
public Boolean get() {
return getWrappedProxy().getBoolean();
}
#Override
public void set(Boolean value) {
getWrappedProxy().setBoolean(value);
}
}
... and Integer ...
public class RemoteIntegerBuilder extends RemoteVariable<Integer> implements RemoteVariableBuilder {
public RemoteIntegerBuilder(RemoteDeviceProxy wrappedProxy) {
super(wrappedProxy);
}
#SuppressWarnings("unchecked")
#Override
public <T> RemoteVariable<T> buildNewVariable(RemoteDeviceProxy wrappedProxy) {
return (RemoteVariable<T>) new RemoteIntegerBuilder(wrappedProxy);
}
#Override
public Integer get() {
return getWrappedProxy().getInteger();
}
#Override
public void set(Integer value) {
getWrappedProxy().setInteger(value);
}
}
actually eclipse created most of the code once it knew base class and interface.
The final step was to create a factory
public class RemoteVariableFactory {
private static final Map<String, RemoteVariableBuilder> BUILDERS = new HashMap<>();
static {
BUILDERS.put(Boolean.class.getName(), new RemoteBooleanVariable(null));
BUILDERS.put(Integer.class.getName(), new RemoteIntegerBuilder(null));
// add more builders here
}
public static <T> RemoteVariable<T> getRemoteVariable(RemoteDeviceProxy wrappedProxy, Class<T> typeClass) {
RemoteVariableBuilder remoteVariableBuilder = BUILDERS.get(typeClass.getName());
if (remoteVariableBuilder == null) {
return null; // or throw an exception whichever is better in your case
}
return remoteVariableBuilder.buildNewVariable(wrappedProxy);
}
}
Now we are ready to create new RemoteVariables...
RemoteVariable<Boolean> var1 = RemoteVariableFactory.getRemoteVariable(new RemoteDevice(), Boolean.class);
RemoteVariable<Integer> var2 = RemoteVariableFactory.getRemoteVariable(new RemoteDevice(), Integer.class);
To conclude this let's do a quick comparison to the answer of Eng.Fouad:
Disadvantage:
you need to create a new class for every datatype you provide
Advantage:
you only have to add one line to the static block of the factory and not two new if blocks to the getter and setter in RemoteVariable
get and set do not have to work through the if-else-blocks every time
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.
what I'm trying to do is send a generic method(filter) inside generic object(ItemDelegate) to another generic method(getItem). The problem is that the second method(getItem) can not infer the correct type.
// Generic object
public class ItemDelegate<T> {
public <T> T filter() {
return null;
}
}
// Generic method (receiver):
public static <T> T getItem(ItemDelegate<T> delegate) {
T item = delegate.filter();
//... do something
return item;
}
// Usage in code:
getItem(new ItemDelegate<String>() {
public String filter() {
return "Hi!";
}
}
this code generates a compile error in getItem:
type parameters of T cannot be determined; no unique maximal instance exists for type variable T with upper bounds T,java.lang.Object
Can this even be done in java or is there a better way.
Thanks.
This works for me:
// Generic object
public class ItemDelegate<T> {
public T filter() {
return null;
}
// Generic method (receiver):
public static <R> R getItem(ItemDelegate<R> delegate) {
R item = delegate.filter();
// ... do something
return item;
}
public static void main(String[] args) {
// Usage in code:
getItem(new ItemDelegate<String>() {
#Override
public String filter() {
return "Hi!";
}
});
}
}
It is not clear to me what you want - do you want to make filter generic on a different parameter than that of the generic class ItemDelegate<T>? Then I guess you should use a different parameter name as a minimum:
public class ItemDelegate<T> {
public <U> U filter() {
return null;
}
}
or if you need the same parameter, don't redeclare it:
public class ItemDelegate<T> {
public T filter() {
return null;
}
}
Another problem is, you don't actually override filter in your anonymous class here
getItem(new ItemDelegate<String>() {
public String filter(ResultSet x) throws SQLException {
return "Hi!";
}
}
since this filter has a parameter and throws an exception.
These two issues together mean that the compiler can't infer T for ItemDelegate.filter.