I have a class that uses wild cards and generics to return a cache object and I'm trying to mock it but I get the following error:
Unfinished stubbing detected here:
-> at com.demo.MyTestTest.initTests(MyTest.java:232)
E.g. thenReturn() may be missing.
Examples of correct stubbing:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod();
my generic class is:
public class AsyncCaffeineCacheManager {
private final Map<String, AsyncCache<?, ?>> cacheMap;
#Getter
private final List<String> cacheNames;
private AsyncCaffeineCacheManager(Map<String, AsyncCache<?, ?>> cacheMap, List<String> cacheNames) {
this.cacheMap = cacheMap;
this.cacheNames = cacheNames;
}
#SuppressWarnings("unchecked")
public <K, V> AsyncCache<K, V> getCache(String cacheName) {
return (AsyncCache<K, V>) cacheMap.get(cacheName);
}
......
}
and my test class:
public class MyTest {
#BeforeEach
public void initTests() {
doReturn(new NoOpAsyncCache<Integer, MyValue>("cacheName"))
.when(asyncCaffeineCacheManager.getCache(anyString()));
}
}
I also created a NoOpAsyncCache which is default implementation:
#Getter
public class NoOpAsyncCache<K, V> implements AsyncCache<K, V> {
private final String cacheName;
public NoOpAsyncCache(String cacheName) {
this.cacheName = cacheName;
}
#Override
public #Nullable CompletableFuture<V> getIfPresent(K key) {
return null;
}
#Override
public CompletableFuture<V> get(K key, Function<? super K, ? extends V> mappingFunction) {
return null;
}
#Override
public CompletableFuture<V> get(K key, BiFunction<? super K, ? super Executor, ? extends CompletableFuture<? extends V>> mappingFunction) {
return null;
}
......
}
I also tried to create a real one, but it didn't work.
Would love to hear some ideas.
Turns out it was not an issue with generics.
the when(..) was wrong:
instead of:
.when(asyncCaffeineCacheManager.getCache(anyString()));
it should have been:
.when(asyncCaffeineCacheManager).getCache(anyString());
also NoOpAsyncCache didn't work well for me, had to use a real implementation
doReturn(Caffeine.newBuilder().buildAsync())
.when(asyncCaffeineCacheManager).getCache(anyString());
Related
How can I put a delay Spring repository method execution to Map?
Is it possible to do something like this?
final Map<T, Function<T, R>> maps = new LinkedHashMap<>();
maps.put(product, productRepository::save);
maps.put(client, clientRepository::save);
The productRepository and the clientRepository there're Spring repositories.
You can do it, for instance like that:
public class Sample {
public static void main(String[] args) {
Demo<Integer, String> demo = new Demo<>();
demo.put(1, String::valueOf);
System.out.println(demo.get(1).apply(15).getClass());
}
static class Demo<T, R> {
private final Map<T, Function<T, R>> maps = new ConcurrentHashMap<>();
void put(T key, Function<T, R> mapper) {
maps.put(key, mapper);
}
Function<T, R> get(T key) {
return maps.get(key);
}
}
}
Output: class java.lang.String
I have a problem here that is probably very simple to solve, but unfortunately I'm still a bit stumped.
public final class ImmutableMap<K, V> extends AbstractReadableMap<K, V>
{
public ImmutableMap(Entry<K, V>[] entry)
{
super();
}
}
I have this class ImmutableMap<K, V> and its constructor.
public interface ReadableMap<K, V>
{
public abstract ImmutableMap<K, V> asImmutableMap();
}
I have this interface ReadableMap<K, V> and its abstract method asImmutableMap.
public abstract class AbstractReadableMap<K, V> implements ReadableMap<K, V>
{
protected Entry<K, V>[] entries;
public ImmutableMap<K, V> asImmutableMap()
{
return ImmutableMap(entries);
}
}
And finally I have this class AbstractReadableMap<K, V> where I'd like to implement the method asImmutableMap(). Unfortunately I get the error The method ImmutableMap(Entry<K,V>[]) is undefined for the type AbstractReadableMap<K,V>.
public class Launcher
{
public static void main(String[] args)
{
MutableMap<String, Integer> map = new MutableMap<String, Integer>();
putEntries(map);
printEntries(map);
ImmutableMap<String, Integer> immutableMap = asImmutableMap(map);
printEntries(immutableMap);
}
}
Same here: The method asImmutableMap(MutableMap<String,Integer>) is undefined for the type Launcher
Why is that and how can I fix it?
Thanks a lot in advance!
I am trying to write a class that works as a type of map. The children of this class have layers of mapping on top of basic functionality. Something like the below:
public interface MyMap<K, V> {
public V get(K key);
}
public interface Client<K, V> {
public V fetch(K key);
}
public class ComplexKey<T> {
private T _key;
public ComplexKey(T key) {
_key = key;
}
T getKey() {
return _key;
}
}
public class BasicMyMap<K, V> implements MyMap<K, V> {
private final Client<K, V> _client;
public BasicMyMap(Client<K, V> client) {
_client = client;
}
#Override
public V get(K key) {
return _client.fetch(key);
}
}
/**
*
* #param <MK> mapped key
* #param <K> key
* #param <V> value
*/
public class ComplexKeyMyMap<MK extends ComplexKey, K, V> implements BasicMyMap<MK, V> {
private Function<K, MK> _mapper;
public ComplexKeyMyMap(Client<MK, V> client, Function<K, MK> mapper) {
super(client);
_mapper = mapper;
}
public V get(K rawKey) {
return super.get(_mapper.apply(rawKey));
}
}
public static void main(String[] args) {
BasicMyMap<String, String> basicMyMap = new BasicMyMap<>(key -> "success");
assert "success".equals(basicMyMap.get("testing"));
ComplexKeyMyMap<ComplexKey, String, String> complexKeyMyMap = new ComplexKeyMyMap<>(key -> "success", (Function<Object, ComplexKey>) ComplexKey::new);
assert "success".equals(complexKeyMyMap.get("testing"));
}
In addition to the key mapping, I would like to add a layer for mapping the value that is returned as well.
So question is:
What is the common approach to this problem? I have encountered this pattern multiple times and have not found a great solution.
How can I achieve this such that the users of these classes can just rely on the MyMap interface definition.
Thanks for the help.
I now came several times across this problem and always kinda solved this with some casts and #SuppressWarnings annotations.
The relevant interfaces / abstract classes:
public abstract class Data { }
public interface DataOperations {
boolean isValid();
}
public interface DataOperationsFactory<T extends Data> {
Class<T> getDataClass();
DataOperations getOperations(T data);
}
Example Implementations:
public class DataImpl1 extends Data {
public String foo;
}
public class DataImpl1Operations implements DataOperations {
private DataImpl1 data;
public DataImpl1Operations(DataImpl1 data) {
this.data = data;
}
public boolean isValid() {
return data.foo != null;
}
}
public class DataImpl1OperationsFactory extends DataOperationsFactory<DataImpl1> {
public Class<DataImpl1> getDataClass() {
return DataImpl1.class;
}
DataOperations getOperations(DataImpl1 data) {
return new DataImpl1Operations(data);
}
}
Using this pattern, I can decide whether I need to create a new DataImpl1Operations everytime. Or maybe use a final static NO_OP implementation or what have you.
The Code:
Now I'd like to put all those factories inside a Map<Class<T>, DataOperationsFactory<T>> (constructor). And afterwards read from it (getOps method).
public class Test {
Map<Class<?>, DataOperationsFactory<?>> map;
public Test(List<DataOperationsFactory<?>> fs) {
for(DataOperationsFactory<?> f : fs) {
map.put(f.getDataClass(), f);
}
}
#SuppressWarnings("unchecked")
public <T extends Data> DataOperations getOps(T data) {
// --> Here I need to do an unchecked cast <--
DataOperationsFactory<? super T> f =
(DataOperationsFactory<? super T>) map.get(data.getClass());
return f.getOperations(data);
}
}
Is there any way doing this without unchecked casting?
You can delegate to a private method that captures the type, so it can be used to reliably cast to the correct Data subclass:
Map<Class<?>, DataOperationsFactory<?>> map;
// Unchanged
public Test(List<DataOperationsFactory<?>> fs) {
for(DataOperationsFactory<?> f : fs) {
map.put(f.getDataClass(), f);
}
}
public DataOperations getOps(Data data) {
DataOperationsFactory<?> f = map.get(data.getClass());
return getOperations(f, data);
}
private static <T extends Data> DataOperations getOperations(DataOperationsFactory<T> f,
Data data) {
return f.getOperations(f.getDataClass().cast(data));
}
I have some difficulty to simplify more the problem. Sorry if they are too many code here.
I try to improve the architecture of the code above because I hate warning and cast and I feel something wrong.
Now, the code.
I have a util class with these two parametrized methods (same signature as OpenJPA's CriteriaBuilder...)
public class MyUtil {
public void equal(List<?> l, Object value) {
// do something (see CriteriaBuilder.equal method)
}
public <Y extends Comparable<? super Y>> void greaterThan(List<? extends Y> l, Y value) {
// do something (see CriteriaBuilder.greaterThan method)
}
}
Then, I want to be able to abstract them to call it via an interface.
public interface IOperation<T> {
// maybe make this method generic ? but how ?
public abstract void doOp(List<T> l, T value);
}
public abstract class AbstractOperation<T> implements IOperation<T> {
protected MyUtil myUtil;
}
public class EqualOp extends AbstractOperation<Object> {
#Override
public void doOp(List<Object> path, Object value) {
myUtil.equal(path, value);
}
}
public class GreaterThanOp<T extends Comparable<? super T>> extends AbstractOperation<T> {
#Override
public void doOp(List<T> path, T value) {
myUtil.greaterThan(path, value);
}
}
I create a factory
public class OperationFactory {
private static OperationFactory instance;
public static OperationFactory getInstance() {...}
public IOperation<?> get(String op) {
if ("=".equals(op)) {
return new EqualOp();
} else if (">".equals(op)) {
return new GreaterThanOp<Comparable<? super Object>>();
}
throw new InvalidParameterException();
}
}
Then I use it :
public class Client {
public void needOp(String op) {
IOperation<String> operation = (IOperation<String>) OperationFactory.getInstance().get(op); // How to avoid this cast ?
List<String> l = null;
operation.doOp(l, "a string");
}
}
My question is : is it possible to avoid this cast in the Client class ? How ? Is there a way to have a better architecture ?
Thanks for reading
I'm assuming you can require your type to be Comparable.
Parameterize EqualOp like GreaterThanOp:
public class EqualOp<T extends Comparable<T>> extends AbstractOperation<T> {
#Override public void doOp(List<T> path, T value) ...
And define get() like this:
public <T extends Comparable<T>> IOperation<T> get(String op) {
if ("=".equals(op)) {
return new EqualOp<T>();
} else if (">".equals(op)) {
return new GreaterThanOp<T>();
}
...