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.
Related
Currently have an issue getting a specific object in an arraylist. So I have multiple classes that implements the same interface, and I create objects of the different classes. The problem is that I don't know how to differentiate the classes in the arraylist.
ArrayList<Interface> arraylist = new ArrayList<>();
public static void main(String[] args) {
addInterface(new interfaceA());
addInterface(new interfaceB());
addInterface(new interfaceC());
}
public static void addInterface(Interface foo) {
arraylist.add(foo);
}
Let say that I want to get interfaceA(), I could call it by arraylist.get(0) but I don't want to hardcode it. Each class has the same methods but the code is different.
I would use a Map instead of a List. In this case an IdentityHashMap is a good fit.
interface Thing {
}
IdentityHashMap<Class<? extends Thing>, Thing> things = new IdentityHashMap<>();
class ThingA implements Thing {
#Override
public String toString() {
return "ThingA{}";
}
}
class ThingB implements Thing {
#Override
public String toString() {
return "ThingB{}";
}
}
class ThingC implements Thing {
#Override
public String toString() {
return "ThingC{}";
}
}
public void registerThing(Thing thing) {
things.put(thing.getClass(), thing);
}
public void test(String[] args) {
registerThing(new ThingA());
registerThing(new ThingB());
registerThing(new ThingC());
System.out.println(things.get(ThingB.class));
}
You could filter using a predicate, by checking runtime classes:
List<Interface> interfaceAList = arraylist.stream()
.filter(e -> InterfaceA.class.isInstance(e))
.collect(Collectors.toList());
public Interface getInterfaceA(List<Interface> interfaces) {
for (Interface i : interfaces) {
if (i instanceof InterfaceA)
return i;
}
return null;
}
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.
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 asked before for an example "annotation processor" that would generate a Proxy/Delegate for an interface, but got no answer, and did not find anything on the Internet, so I made my own.
So far it worked well, until I tried to use generics inside a super-interface. If I use generics in the annotated interface, it works fine (more by accident than by design). But if the annotated interface extends another interface that takes a generic type parameter, that parameter is not "bound" to the type that the annotated interface use when extending the super-interface. Example:
public interface TestFragment<E> {
void test(E dummy);
}
#CreateWrapper
public interface TestService extends TestFragment<String> {
double myOwnMethod();
}
This would generate:
// ...
public void test(final E dummy) {
wrapped.test(dummy);
}
// ...
instead of the correct:
// ...
public void test(final String dummy) {
wrapped.test(dummy);
}
// ...
The code that generates the parameters in the generated methods look like this:
int count = 0;
for (VariableElement param : method.getParameters()) {
if (count > 0) {
pw.print(", ");
}
count++;
pw.printf("final %s %s", param.asType().toString(),
param.getSimpleName().toString());
}
Is there a way to do this?
Have a look at http://docs.oracle.com/javase/6/docs/api/javax/lang/model/util/Types.html#asMemberOf%28javax.lang.model.type.DeclaredType,%20javax.lang.model.element.Element%29
Might be helpful. I used it to solve a very similar problem.
This can be quite simple if you follow Ryan Walls suggestion of using asMemberOf
ExecutableType methodType = (ExecutableType) typeUtil
.asMemberOf((DeclaredType) theAnnotatedClass.asType(), method);
int count = 0;
for (VariableElement param : method.getParameters()) {
if (count > 0) {
pw.print(", ");
}
TypeMirror actualParamType = methodType.getParameterTypes().get(count);
pw.printf("final %s %s", actualParamType.toString(),
param.getSimpleName().toString());
count++;
}
What you need is substitution, given a map of type variables to type arguments. In this case, E->String. Replace any E in any type with String
There is no such support in javax.lang.model.util.Types, you need to roll your own. Basically
void print(TypeMirror type, Map<TypeVariable,TypeMirror> substitution)
if(substitution.containsKey(type)) // type is a var, E
print( substitution.get(type) ); // String
else if(type instanceof DeclaredType) // e.g. List<E>
print( type.asElement().getSimpleName() ); // List
for(TypeMirror arg : type.getTypeArguments() ) // E
print(arg, substitution)
etc. something like that
Copy-paste of my original answer:
This seems to be a common question so, for those arriving from Google: there is hope.
The Dagger DI project is licensed under the Apache 2.0 License and contains some utility methods for working with types in an annotation processor.
In particular, the Util class can be viewed in full on GitHub (Util.java) and defines a method public static String typeToString(TypeMirror type). It uses a TypeVisitor and some recursive calls to build up a string representation of a type. Here is a snippet for reference:
public static void typeToString(final TypeMirror type, final StringBuilder result, final char innerClassSeparator)
{
type.accept(new SimpleTypeVisitor6<Void, Void>()
{
#Override
public Void visitDeclared(DeclaredType declaredType, Void v)
{
TypeElement typeElement = (TypeElement) declaredType.asElement();
rawTypeToString(result, typeElement, innerClassSeparator);
List<? extends TypeMirror> typeArguments = declaredType.getTypeArguments();
if (!typeArguments.isEmpty())
{
result.append("<");
for (int i = 0; i < typeArguments.size(); i++)
{
if (i != 0)
{
result.append(", ");
}
// NOTE: Recursively resolve the types
typeToString(typeArguments.get(i), result, innerClassSeparator);
}
result.append(">");
}
return null;
}
#Override
public Void visitPrimitive(PrimitiveType primitiveType, Void v) { ... }
#Override
public Void visitArray(ArrayType arrayType, Void v) { ... }
#Override
public Void visitTypeVariable(TypeVariable typeVariable, Void v)
{
result.append(typeVariable.asElement().getSimpleName());
return null;
}
#Override
public Void visitError(ErrorType errorType, Void v) { ... }
#Override
protected Void defaultAction(TypeMirror typeMirror, Void v) { ... }
}, null);
}
I am busy with my own project which generates class extensions. The Dagger method works for complex situations, including generic inner classes. I have the following results:
My test class with field to extend:
public class AnnotationTest
{
...
public static class A
{
#MyAnnotation
private Set<B<Integer>> _bs;
}
public static class B<T>
{
private T _value;
}
}
Calling the Dagger method on the Element the processor provides for the _bs field:
accessor.type = DaggerUtils.typeToString(element.asType());
The generated source (custom, of course). Note the awesome nested generic types.
public java.util.Set<AnnotationTest.B<java.lang.Integer>> AnnotationTest.A.getBsGenerated()
{
return this._bs;
}
EDIT: adapting the concept to extract a TypeMirror of the first generic argument, null otherwise:
public static TypeMirror getGenericType(final TypeMirror type)
{
final TypeMirror[] result = { null };
type.accept(new SimpleTypeVisitor6<Void, Void>()
{
#Override
public Void visitDeclared(DeclaredType declaredType, Void v)
{
List<? extends TypeMirror> typeArguments = declaredType.getTypeArguments();
if (!typeArguments.isEmpty())
{
result[0] = typeArguments.get(0);
}
return null;
}
#Override
public Void visitPrimitive(PrimitiveType primitiveType, Void v)
{
return null;
}
#Override
public Void visitArray(ArrayType arrayType, Void v)
{
return null;
}
#Override
public Void visitTypeVariable(TypeVariable typeVariable, Void v)
{
return null;
}
#Override
public Void visitError(ErrorType errorType, Void v)
{
return null;
}
#Override
protected Void defaultAction(TypeMirror typeMirror, Void v)
{
throw new UnsupportedOperationException();
}
}, null);
return result[0];
}
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.