Matching custom exceptions - java

The Javadoc gives this example for the matches method:
assertThat(player).matches(p -> p.isRookie());
And indeed, when I define a dummy class Player, the above statement compiles ok. However, when I define a class that derives from Exception, then the following doesn't compile:
public class MyCustomException extends Exception {
public boolean isMyCustomFieldSet() { return true; }
}
...
MyCustomException myCustomException = new MyCustomExcpetion();
assertThat(myCustomException).matches(e -> e.isMyCustomFieldSet());
I can make it compile by using a cast:
assertThat(myCustomException).matches(e -> ((MyCustomException)e).isMyCustomFieldSet());
but that cast looks "ugly" and a bit of a hack to work around some sort of deficiency. Can I make it compile in a "nicer" way, i.e. without using a cast?

The issue is in Assertions, it declares AbstractThrowableAssert<?, ? extends Throwable> assertThat(Throwable t) instead of <T> AbstractThrowableAssert<?, T extends Throwable> assertThat(T t)
But unfortunately this can not be done because of the following existing method that clashes with it: public static <T> ObjectAssert<T> assertThat(T actual).
Casting is a solution, I agree it is not super elegant.
What I would do in that case is simply:
assertThat(myCustomException.isMyCustomFieldSet()).isTrue();
or to keep assertions on myCustomException directly:
assertThat(myCustomException).hasFieldOrPropertyWithValue("myCustomFieldSet", true)
.hasFieldOrPropertyWithValue("myOtherField", "foo");
The drawback here is accessing fields by name which is not refactoring friendly.

I don't think you'll be able to find a shorter way.
The issue is that
assertThat(new Player())
returns an ObjectAssert<Player>, with its matches signature being matches(Predicate<? super Player>).
However,
assertThat(new MyException())
actually calls a different method assertThat which returns an AbstractThrowableAssert<?, ? extends Throwable> with a matches(Predicate<? super Throwable>).
So that explains the issue, but I can't give you a better way to approach it.
I haven't checked whether an open issue exists against it, but it might be worth submitting one if it doesn't.

As my acknowledge, there is no way to using the method isMyCustomFieldSet directly. Because the assert lib using generic class and a generic class cannot extend the Throwable class directly or indirectly.
More info here

Related

When called on a derived class, have a generic method defined in base class return derived class type in Java

I have a utility class for interacting with the Datastore (GAE's in-built Datastore in my case) and it has methods like:
//Class GaeDataUtil
public static <T> Optional<Key<T>> saveEntity(T entity)
(Optional is from the Guava library and Key<T> from Objectify, although I doubt any of this makes a difference.)
I want my (minimal) hierarchy of entities to have a .save() method. So that for:
public class User extends RootEntity
where RootEntity provides:
public Optional<Key<T>> save() {
//Skipping the error-handling.
return GaeDataUtil.saveEntity(this);
}
I can write:
User myUser = new User();
// set some properties
Optional<Key<User>> optKey = myUser.save();
But of course that doesn't work because a call to myUser.save() returns Optional<Key<RootEntity>> not Optional<Key<User>> as I want.
I can avoid this issue by typecasting in User.save() (and Account.save() and Project.save() etc. etc.) and suppressing warnings, but even if there are only (say) 10 entity classes extending RootEntity, that's still a fair bit of boilerplate code to write just to typecast. Also, I think that much of the benefit of having a class hierarchy is lost if I have to write code (however minimal) for every derived class (there will be other, similar methods too).
Is there a better solution to this?
Update: using Java 7.
You will just need to type cast it to the Generic type T in the RootEntity.save() method.
public <T> Optional<Key<T>> save() {
//Skipping the error-handling.
return (Optional<Key<T>> GaeDataUtil.saveEntity(this); // This line will generate a warning.
}
And then when you write,
Optional<Key<User>> optKey = myUser.save();
It will automatically be inferred correctly because of Target Type Inference.
One solution is to parameterize RootEntity something like this:
class RootEntity<Subclass extends RootEntity> {
public Optional<Key<Subclass>> save() {...}
}
Then define your subclass like:
class User extends RootEntity<User> {...}
I've used this pattern before. If there is a slicker solution, I'll be eager to see it. :)
This is what finally worked:
public <T extends RootEntity> Optional<Key<T>> save1() {
#SuppressWarnings("unchecked")
Key<T> key = (Key<T>) ofy().save().entity(this).now();
return Optional.fromNullable(key);
}
Doing this in two steps works (get the Key, then wrap it up in an Optional) --- it let's the Target Type Inference work correctly. Doing it in a single step doesn't:
public <T extends RootEntity> Optional<Key<T>> save2() {
return (Optional<Key<T>>) Optional.fromNullable(ofy().save().entity(this).now());
}
This second form as suggested by #Codebender shows an error (Cannot cast from Optional<Key<RootEntity>> to Optional<Key<T>>), not a warning in Eclipse.
However, the basic idea by #Codebender of using Target Type Inference was sound.

Mockito isA(Class<T> clazz) How to resolve type safety?

in my test I have the following line:
when(client.runTask(anyString(), anyString(), isA(Iterable.class)).thenReturn(...)
isA(Iterable.class) produces warning that it needs unchecked conversion to conform to Iterable<Integer> . What is syntax for that?
isA(Iterable<Integer>.class)
isA((Iterable<Integer>)Iterable.class
do not work.
Any suggestions?
Mockito/Hamcrest and generic classes
Yes, this is a general problem with Mockito/Hamcrest. Generally using isA() with generic classes produces a warning.
There are predifined Mockito matchers for the most common generic classes: anyList(), anyMap(), anySet() and anyCollection().
Suggestions:
anyIterable() in Mockito 2.1.0
Mockito 2.1.0 added a new anyIterable() method for matching Iterables:
when(client.runTask(anyString(), anyString(), anyIterable()).thenReturn(...)
Ignore in Eclipse
If you just want to get rid of the warning in Eclipse. Option exists since Eclipse Indigo:
Window > Preferences > Java > Compiler > Errors/Warnings > Generic
types > Ignore unavoidable generic type problems
Quick Fix with #SuppressWarnings
I suggest you do this if you have the problem only once. I personally don't remember ever needing an isA(Iterable.class).
As Daniel Pryden says, you can limit the #SuppressWarnings to a local variable or a helper method.
Use a generic isA() matcher with TypeToken
This solves the problem for good. But it has two disadvantages:
The syntax is not too pretty and might confuse some people.
You have an additional dependency on the library providing the TypeToken class. Here I used the TypeToken class from Guava. There's also a TypeToken class in Gson and a GenericType in JAX-RS.
Using the generic matcher:
import static com.arendvr.matchers.InstanceOfGeneric.isA;
import static org.mockito.ArgumentMatchers.argThat;
// ...
when(client.runTask(anyString(), anyString(), argThat(isA(new TypeToken<Iterable<Integer>>() {}))))
.thenReturn(...);
Generic matcher class:
package com.arendvr.matchers;
import com.google.common.reflect.TypeToken;
import org.mockito.ArgumentMatcher;
public class InstanceOfGeneric<T> implements ArgumentMatcher<T> {
private final TypeToken<T> typeToken;
private InstanceOfGeneric(TypeToken<T> typeToken) {
this.typeToken = typeToken;
}
public static <T> InstanceOfGeneric<T> isA(TypeToken<T> typeToken) {
return new InstanceOfGeneric<>(typeToken);
}
#Override
public boolean matches(Object item) {
return item != null && typeToken.getRawType().isAssignableFrom(item.getClass());
}
}
Here's what I do:
// Cast from Class<Iterable> to Class<Iterable<Integer>> via the raw type.
// This is provably safe due to erasure, but will generate an unchecked warning
// nonetheless, which we suppress.
#SuppressWarnings("unchecked")
Class<Iterable<Integer>> klass
= (Class<Iterable<Integer>>) (Class) Iterable.class;
// later
isA(klass) // <- now this is typesafe
You can add #SuppressWarnings("unchecked") above the statement. No other way but if it bothers you, you can move the cast to a helper method.
There is no way to do this. To simplify, you can't initialize this variable without warning :
Class<Iterable<Integer>> iterableIntegerClass = ?
One solution might be to use the pseudo-typedef antipattern,
,you create and use an IntegerIterable interface
interface IntegerIterable extends Iterable<Integer> {}
then
isA(IntegerIterable.class)
will no more produce warning. But you will have to extend the class implementing Iterable to let them implements IntegerIterable :) For example :
public class IntegerArrayList extends ArrayList<Integer> implements IntegerIterable {}
Mmm tasty...
So, i will sugest you to consider to just paper over the cracks by adding to your method :
#SuppressWarnings("unchecked")

Why cannot generic extend a non-generic class in Java?

It looks like a generic class in java cannot extend a regular non-generic class. What is the reason for that? Is there any workaround?
I was mistaken. As ColinD pointed out my problem was actually with exceptions. Can anybody explain why generic exceptions are not allowed in Java?
public class A {
}
public class B<T> extends A {
}
Works without any problems.
Java seems to do it :
public abstract class AbstractCollection<E>
extends Object
implements Collection<E>
Do you have some code, so we can see the problem?
Because exceptions catching require the jvm to know the exact type of exception at runtime (reification) which is not possible in java because all type parameter information is erased by the compiler
You can! - with certain restrictions. Exceptions are one of those restrictions. You can't make them generic. Erasure removes the exception type information preventing the exception hierarchy from working if you threw generic versions of exceptions. Too bad :(.
Consider this:
import org.apache.commons.collections.set.UnmodifiableSet;
import org.apache.commons.beanutils.BeanMap;
//Can't do this:
//public class MyBeanMap<K, V> extends BeanMap implements Map<K,V>{
//Can do this:
public class MyBeanMap<K, V> extends BeanMap {
//Can't make actual method calls return generic types.
public V get(V arg0) {//Name clash
...
return (V)retval;
}
//Also can't do this:
#override
public V get(V arg0) {//Name clash
return (V)retval;
}
}
I guess you could throw UnsupportedOperation exceptions in overridden methods for the existing interface, and implement your own new generic methods:
public V getGeneric(V){
...
}
but that seems a lot uglier than implementing a facade pattern and just extending the map code, but that is a LOT of intermediate code to create a facade for.

Guice generics - how can I make it less ugly?

I have an interface Producer<T> and a concrete FooProducer that implements Producer<Foo>. Binding this in guice looks ugly as sin:
bind(new TypeLiteral<Producer<Foo>>() {}).to(FooProducer.class);
I have lots of these such bindings. I have tried the following:
static <T> TypeLiteral<Producer<T>> producer() {
return new TypeLiteral<Producer<T>>(){};
}
With calls made in this way:
bind(ContainingClass.<Foo>producer()).to(FooProducer.class);
But it gives an error along the lines of Producer<T> is not specific enough....
Am I going about this in the wrong way?
Instead of
bind(new TypeLiteral<Producer<Foo>>() {}).to(FooProducer.class);
try a convenience method like
static <T> Key<Producer<T>> producerOf(Class<T> type) {
return (Key<Producer<T>>)Key.get(Types.newParameterizedType(Producer.class,type));
}
and then in your module
bind(producerOf(Foo.class)).to(FooProducer.class);
That unchecked cast should be safe. Key is com.google.inject.Key and Types is com.google.inject.util.Types.
good luck
You can save 8 characters by typing new Key<Producer<Foo>>(){} rather than new TypeLiteral<Producer<Foo>>(){}. Or by using the equivalent #Provides method:
#Provides
public Producer<Foo> provideFooProducer(FooProducer fooProducer) {
return fooProducer;
}
I believe that due to how TypeLiterals work, you have to actually write new TypeLiteral<Producer<Foo>>(){} or the necessary type information will not be available. They utilize the fact that a class that has fully specified its generic types can have information on those types retrieved. When you write new TypeLiteral<Producer<T>>(){}, you aren't specifying what T is, so that information isn't available.
It's subjective, but I don't think creating a type literal looks too ugly, considering what it does.
As an aside, I don't know what your Producer interface does, but if it is just used for producing instances of T (with a method that takes no arguments), you could use Guice's Provider interface instead. Then you just have to do:
bind(Foo.class).toProvider(FooProvider.class);
And you can inject a Foo or a Provider<Foo> anywhere.

Java generics question - Class<T> vs. T?

I'm using Hibernate validator and trying to create a little util class:
public class DataRecordValidator<T> {
public void validate(Class<T> clazz, T validateMe) {
ClassValidator<T> validator = new ClassValidator<T>(clazz);
InvalidValue[] errors = validator.getInvalidValues(validateMe);
[...]
}
}
Question is, why do I need to supply the Class<T> clazz parameter when executing new ClassValidator<T>(clazz)? Why can't you specify:
T as in ClassValidator<T>(T)?
validateMe.getClass() as in ClassValidator<T>(validateMe.getClass())
I get errors when I try to do both options.
Edit: I understand why #1 doesn't work. But I don't get why #2 doesn't work. I currently get this error with #2:
cannot find symbol
symbol : constructor ClassValidator(java.lang.Class<capture#279 of ? extends java.lang.Object>)
location: class org.hibernate.validator.ClassValidator<T>
Note: Hibernate API method is (here)
Because T is not a value - it's just a hint for the compiler. The JVM has no clue of the T. You can use generics only as a type for the purposes of type checking at compile time.
If the validate method is yours, then you can safely skip the Class atribute.
public void validate(T validateMe) {
ClassValidator<T> validator =
new ClassValidator<T>((Class<T>) validateMe.getClass());
...
}
But the ClassValidator constructor requires a Class argument.
Using an unsafe cast is not preferred, but in this case it is actually safe if you don't have something like this:
class A {..}
class B extends A {..}
new DataRecordValidator<A>.validate(new B());
If you think you will need to do something like that, include the Class argument in the method. Otherwise you may be getting ClassCastException at runtime, but this is easily debuggable, although it's not quite the idea behind generics.
Because ClassValidator is requiring a Class object as its parameter, NOT an instance of the class in question. Bear in mind you might be able to do what you're trying to do with this code:
ClassValidator<? extends T> validator = new ClassValidator<? extends T>(validateMe.getClass());

Categories

Resources