Assume we have the following interface and implementations:
interface Matcher<T>{
boolean matches(T arg);
}
class NumberMatcher<T extends Number> implements Matcher<T>{
#Override
public boolean matches(T arg){...}
}
class StringMatcher extends Matcher<String>{
#Override
public boolean matches(String arg){ ...}
}
class CustomMatcher extends NumberMatcher<Integer> {
public boolean matches(String arg){...}
#Override
public boolean matches(Integer arg){...}
}
What I need is the type of the parameter of the matches(T) method of a given Matcher implementation.
NumberMatcher numberMatcher = new NumberMatcher<Long>();
StringMatcher stringMatcher = new StringMatcher();
CustomMatcher customMatcher = new CustomMatcher();
Matcher<Date> dateMatcher = new Matcher<Date>(){...};
getArgumentType(numberMatcher) // should return Number.class
getArgumentType(stringMatcher) // should return String.class
getArgumentType(customMatcher) // should return Integer.class
getArgumentType(dateMatcher ) // should return Object.class
Here is a implementation that works except of the CustomMatcher case, cause it fails to detect the overriden matches(..) method and returns String.class instead of Integer.class.
Class<?> getArgumentType(Matcher<?> matcher) {
Method[] methods = matcher.getClass().getMethods();
for (Method method : methods) {
if (isMatchesMethod(method)) {
return method.getParameterTypes()[0];
}
}
throw new NoSuchMethodError("Method 'matches(T)' not found!");
}
private boolean isMatchesMethod(Method method) {
if (!isPublic(method.getModifiers()))
return false;
if (method.getParameterCount() != 1)
return false;
return method.getName().equals("matches");
}
EDIT:
I am looking for a solution that doesn't need to specify the argument type like this:
interface Matcher<T>{
boolean matches(T arg);
Class<T> argumentType();
}
As long as you can edit the implementations, you can use a marker annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface ThisIsTheOne {
}
public class CustomMatcher extends NumberMatcher<Integer> {
#Override
#ThisIsTheOne
public boolean matches(Integer arg){ return true; }
public boolean matches(String arg){ return true; }
}
private static boolean isMatchesMethod(Method method) {
if (method.getAnnotation(ThisIsTheOne.class) != null) {
return true;
}
// do the same as before, so it works on non-annotated methods too
}
This will return Integer.class for CustomMatcher.
I don't think there's a way to retrieve this information at runtime, since Method-s don't know where they come from. This is probably intentional, as multiple interfaces can define the same method signature.
Related
I have a Java class with a property that can be either a String, a boolean or a List.
What would be the best approach to declare that property type? Knowing that I can only know its type at Runtime.
My first approach was to define that property with type Object, but not sure if there's a better way to achieve this.
private final String expression;
private Object expressionValue;
ParsedExpression(String expression, Person person) {
this.expression= expression;
expressionEvaluator(person);
}
private void expressionEvaluator(Person person) {
switch (this.expression) {
case "name":
expressionValue = person.getName();
break;
case "adult":
expressionValue = person.isAdult();
break;
case "addresses":
expressionValue = person.getAddresses();
break;
default:
throw new RuntimeException("Property does not exist on type Person");
}
}
If you have a very few types and not going to change them you can use a generic class with a private constructor and a few factory methods which allow creating an instance only with specified type parameters:
public final class ExpressionValue<T> {
private final T value;
private ExpressionValue(T value) {this.value = value;}
public Optional<String> getAsString() {
return (value instanceof String) ? Optional.of((String)value) : Optional.empty();
}
public Optional<Boolean> getAsBoolean() {
return (value instanceof Boolean) ? Optional.of((Boolean) value) : Optional.empty();
}
// in this context empty collection and empty optional mean different things
#SuppressWarnings("OptionalContainsCollection")
public Optional<List<?>> getAsList() {
return (value instanceof List) ? Optional.of((List<?>) value) : Optional.empty();
}
public void use(Consumer<? super String> stringUser, Consumer<? super Boolean> booleanUser, Consumer<? super List<?>> listUser) {
getAsString().ifPresent(stringUser);
getAsBoolean().ifPresent(booleanUser);
getAsList().ifPresent(listUser);
}
public static ExpressionValue<String> fromString(String string) {
return new ExpressionValue<>(string);
}
public static ExpressionValue<Boolean> fromBoolean(boolean bool) {
return new ExpressionValue<>(bool);
}
public static ExpressionValue<List<?>> fromList(List<?> list) {
return new ExpressionValue<>(list);
}
}
If you have many available types or need more flexibility of types you can use a hierarchical approach. In this case, you need to create an interface with common String, boolean and List methods, and then create implementations of this interface with all available type parameters. It may look like this:
public interface ExpressionValue<T> {
boolean check();
}
public abstract class ExpressionValueSkeleton<T> implements ExpressionValue<T> {
private T value;
public ExpressionValueSkeleton(T value) {
this.value = value;
}
protected T getValue() {
return value;
}
}
public class StringExpressionValue extends ExpressionValueSkeleton<String> {
public StringExpressionValue(String value) {
super(value);
}
#Override
public boolean check() {
return !getValue().isEmpty();
}
}
public class BooleanExpressionValue extends ExpressionValueSkeleton<Boolean> {
public BooleanExpressionValue(Boolean value) {
super(value);
}
#Override
public boolean check() {
return getValue();
}
}
public class ListExpressionValue<E> extends ExpressionValueSkeleton<List<E>> {
public ListExpressionValue(List<E> value) {
super(value);
}
#Override
public boolean check() {
return !getValue().isEmpty();
}
}
If you want perform some operations which are available only for some types you can use Acyclic Visitor pattern.
I have a doubt in my code :
public abstract class Jogador {
String nome;
int pontos;
Jogador (String n) {
nome = n;
}
void aumentaPontos () {
pontos++;
}
abstract <U extends Jogador> boolean melhor (U outro);
}
class JogadorAdivinha extends Jogador {
JogadorAdivinha (String n) {
super(n);
}
boolean melhor (JogadorAdivinha outro) {
if (this.pontos > outro.pontos)
return true;
return false;
}
}
class JogadorMemoria extends Jogador {
int rodadasGanhas;
JogadorMemoria(String n) {
super(n);
}
boolean melhor(JogadorMemoria outro) {
if (this.rodadasGanhas > outro.rodadasGanhas)
return true;
return false;
}
void aumentaRodadasGanhas() {
rodadasGanhas++;
}
}
I'll have compilation problem at both the child classes of Jogador.
But as you can see, only JogadorMemoria has rodadasGanhas.
So, I want to know a way to handle this situation .... if I put as parameter the class Jogador for the method melhor() , I won't be able to receive the children ...
What can I do about it to override the abstract method and to not create a bad smell ??
If you want to implement a method like this in subclasses:
abstract <U extends Jogador> boolean melhor (U outro);
You have to provide override-equivalent implementations, like:
<U extends Jogador> boolean melhor (U outro) { return true; }
You can't drop type variables in subclasses, as the abstract method's declaration says that it has to be able to accept any instance of Jogador as a parameter to the melhor method.
If you want to have specific parameter types on those methods, you define the type variable at class-level:
public abstract class Jogador<U extends Jodador<U>> {
abstract boolean melhor (U outro);
}
and then you can implement this in the subclasses:
class JogadorAdivinha extends Jogador<JogadorAdivinha> {
boolean melhor (JogadorAdivinha outro) { return true; }
}
I'm using Guava's LineProcessor interface when reading lines from files. I've created my class called Line Loader which will store lines read. I want it to be generic on choice of collection lines should be stored in so I wrote something like this:
public abstract class LineLoader<T> implements LineProcessor<Collection<T>> {
private final Collection<T> result;
public LineLoader() {
this.result = init();
}
protected boolean add(final T line) {
return result.add(line);
}
#Override
public boolean processLine(final String line) throws Exception {
final T data = parser.parseLine(line);
if (data == null) {
return false;
}
return add(data);
}
#Override
public Collection<T> getResult() {
return result;
}
protected abstract Collection<T> init();
}
where with init() method I force subclasses to chose type of collection, for example:
public abstract class LinkedLineLoader<T> extends LineLoader<T> {
#Override
protected Collection<T> init() {
return new LinkedList<T>();
}
}
I planned on doing this:
public class LineLoader<T> implements LineProcessor<C<T> extends Collection<T>> {
private final C<T> result;
public LineLoader() {
result = new C<T>();
}
protected boolean add(final T line) {
return result.add(line);
}
#Override
public boolean processLine(final String line) throws Exception {
final T data = parser.parseLine(line);
if (data == null) {
return false;
}
return add(data);
}
#Override
public C<T> getResult() {
return result;
}
}
so that latter subclases (if needed) could do:
public class LinkedLineLoader<T> extends LineLoader<LinkedList<T>> {
}
but it's not possible. Is there a clean solution to this problem?
In Java it is not possible to create instances from generic type arguments, because generics are erased at run-time. Also, generic type arguments can not themselves declare additional type arguments like C<T>. Therefore the code you posted is entirely illegal and will not compile:
private final C<T> result; // illegal
result = new C<T>(); // illegal
Aside from that, your declaration of the type arguments itself has some flaws. The following code is no legal Java code:
public class LineLoader<T> implements LineProcessor<C<T> extends Collection<T>>
It should actually look e.g. like this:
public class LineLoader<T, C extends Collection<T>> implements LineProcessor<C>
As a solution to your problem, you could declare your LineLoader as shown above, and add a protected constructor, that takes the generic collection as an argument:
public abstract class LineLoader<T, C extends Collection<T>> implements LineProcessor<C> {
private final C result;
protected LineLoader(C collection) {
result = collection;
}
protected boolean add(final T line) {
return result.add(line);
}
#Override
public boolean processLine(final String line) throws IOException {
final T data = parser.parseLine(line);
if (data == null) {
return false;
}
return add(data);
}
#Override
public C getResult() {
return result;
}
}
Then you can implement your LinkedLineLoader like so:
class LinkedLineLoader<T> extends LineLoader<T, LinkedList<T>> {
public LinkedLineLoader() {
super(new LinkedList<>());
}
}
Is there a way to match any class argument of the below sample routine?
class A {
public B method(Class<? extends A> a) {}
}
How can I always return a new B() regardless of which class is passed into method? The following attempt only works for the specific case where A is matched.
A a = new A();
B b = new B();
when(a.method(eq(A.class))).thenReturn(b);
EDIT: One solution is
(Class<?>) any(Class.class)
Two more ways to do it (see my comment on the previous answer by #Tomasz Nurkiewicz):
The first relies on the fact that the compiler simply won't let you pass in something of the wrong type:
when(a.method(any(Class.class))).thenReturn(b);
You lose the exact typing (the Class<? extends A>) but it probably works as you need it to.
The second is a lot more involved but is arguably a better solution if you really want to be sure that the argument to method() is an A or a subclass of A:
when(a.method(Matchers.argThat(new ClassOrSubclassMatcher<A>(A.class)))).thenReturn(b);
Where ClassOrSubclassMatcher is an org.hamcrest.BaseMatcher defined as:
public class ClassOrSubclassMatcher<T> extends BaseMatcher<Class<T>> {
private final Class<T> targetClass;
public ClassOrSubclassMatcher(Class<T> targetClass) {
this.targetClass = targetClass;
}
#SuppressWarnings("unchecked")
public boolean matches(Object obj) {
if (obj != null) {
if (obj instanceof Class) {
return targetClass.isAssignableFrom((Class<T>) obj);
}
}
return false;
}
public void describeTo(Description desc) {
desc.appendText("Matches a class or subclass");
}
}
Phew! I'd go with the first option until you really need to get finer control over what method() actually returns :-)
There is another way to do that without cast:
when(a.method(Matchers.<Class<A>>any())).thenReturn(b);
This solution forces the method any() to return Class<A> type and not its default value (Object).
If you have no idea which Package you need to import:
import static org.mockito.ArgumentMatchers.any;
any(SomeClass.class)
OR
import org.mockito.ArgumentMatchers;
ArgumentMatchers.any(SomeClass.class)
How about:
when(a.method(isA(A.class))).thenReturn(b);
or:
when(a.method((A)notNull())).thenReturn(b);
the solution from millhouse is not working anymore with recent version of mockito
This solution work with java 8 and mockito 2.2.9
where ArgumentMatcher is an instanceof org.mockito.ArgumentMatcher
public class ClassOrSubclassMatcher<T> implements ArgumentMatcher<Class<T>> {
private final Class<T> targetClass;
public ClassOrSubclassMatcher(Class<T> targetClass) {
this.targetClass = targetClass;
}
#Override
public boolean matches(Class<T> obj) {
if (obj != null) {
if (obj instanceof Class) {
return targetClass.isAssignableFrom( obj);
}
}
return false;
}
}
And the use
when(a.method(ArgumentMatchers.argThat(new ClassOrSubclassMatcher<>(A.class)))).thenReturn(b);
None of the examples above worked for me, as I'm required to mock one method multiple times for different class type parameters.
Instead, this works.
//Handle InstrumentType.class
Mockito.doReturn(new InstrumentTypeMapper() {
#Override
public InstrumentType map(String sourceType) throws Exception {
return InstrumentType.Unknown;
}
}).when(mappingLoader).load(any(ServiceCode.class), argThat(new ArgumentMatcher<Class<InstrumentType>>() {
#Override
public boolean matches(Class<InstrumentType> argument) {
return InstrumentType.class.isAssignableFrom(argument);
}
}));
//Handle InstrumentSubType.class
Mockito.doReturn(new InstrumentSubTypeMapper() {
#Override
public InstrumentSubType map(String sourceType) throws Exception {
return InstrumentSubType.istNone;
}
}).when(mappingLoader).load(any(ServiceCode.class), argThat(new ArgumentMatcher<Class<InstrumentSubType>>() {
#Override
public boolean matches(Class<InstrumentSubType> argument) {
return InstrumentSubType.class.isAssignableFrom(argument);
}
}));
This is the short version:
Mockito.doReturn(new InstrumentTypeMapper() {
#Override
public InstrumentType map(String sourceType) throws Exception {
return InstrumentType.Unknown;
}
}).when(mappingLoader).load(any(ServiceCode.class), argThat((ArgumentMatcher<Class<InstrumentType>>) InstrumentType.class::isAssignableFrom));
Mockito.doReturn(new InstrumentSubTypeMapper() {
#Override
public InstrumentSubType map(String sourceType) throws Exception {
return InstrumentSubType.istNone;
}
}).when(mappingLoader).load(any(ServiceCode.class), argThat((ArgumentMatcher<Class<InstrumentSubType>>) InstrumentSubType.class::isAssignableFrom));
As you can see, I'm using custom ArgumentMatchers together with argThat, not sure if there is a shorter way that also works.
Let's say I have the following class:
public class Test<E> {
public boolean sameClassAs(Object o) {
// TODO help!
}
}
How would I check that o is the same class as E?
Test<String> test = new Test<String>();
test.sameClassAs("a string"); // returns true;
test.sameClassAs(4); // returns false;
I can't change the method signature from (Object o) as I'm overridding a superclass and so don't get to choose my method signature.
I would also rather not go down the road of attempting a cast and then catching the resulting exception if it fails.
An instance of Test has no information as to what E is at runtime. So, you need to pass a Class<E> to the constructor of Test.
public class Test<E> {
private final Class<E> clazz;
public Test(Class<E> clazz) {
if (clazz == null) {
throw new NullPointerException();
}
this.clazz = clazz;
}
// To make things easier on clients:
public static <T> Test<T> create(Class<T> clazz) {
return new Test<T>(clazz);
}
public boolean sameClassAs(Object o) {
return o != null && o.getClass() == clazz;
}
}
If you want an "instanceof" relationship, use Class.isAssignableFrom instead of the Class comparison. Note, E will need to be a non-generic type, for the same reason Test needs the Class object.
For examples in the Java API, see java.util.Collections.checkedSet and similar.
The method I've always used is below. It is a pain and a bit ugly, but I haven't found a better one. You have to pass the class type through on construction, as when Generics are compiled class information is lost.
public class Test<E> {
private Class<E> clazz;
public Test(Class<E> clazz) {
this.clazz = clazz;
}
public boolean sameClassAs(Object o) {
return this.clazz.isInstance(o);
}
}
I could only make it working like this:
public class Test<E> {
private E e;
public void setE(E e) {
this.e = e;
}
public boolean sameClassAs(Object o) {
return (o.getClass().equals(e.getClass()));
}
public boolean sameClassAs2(Object o) {
return e.getClass().isInstance(o);
}
}
I was just trying to do the same thing, and one neat trick i just realized is that you can can try a cast, and if the cast fails, ClassCastException will be thrown. You can can catch that, and do whatever.
so your sameClassAs method should look like:
public boolean sameClassAs(Object o) {
boolean same = false;
try {
E t = (E)o;
same = true;
} catch (ClassCastException e) {
// same is false, nothing else to do
} finally {
return same;
}
}