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!
Related
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());
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.
Although this Piece of code is working, it still grinds my gears:
public static <K, V> Map<K, V> entityListToIdMap(List<? extends BaseEntity<K>> list, Class<K> keyClass) {
Map<K, V> map = new TreeMap<K, V>();
if(list != null){
for (BaseEntity<K> item : list) {
map.put(item.getId(), (V) item);
}
}
return map;
}
What i'm missing is, to tell the method signature, that V extends BaseEntity<K>. This may also lead to the unchecked warning which makes it necessary to cast the item in the value to V.
How can I tell V that it must extend BaseEntity<K>?
based on accepted answer from #Ori Lentz, the complete solution:
public static <K, V extends BaseEntity<K>> Map<K, V> entityListToIdMap(List<V> list, Class<K> keyClass) {
Map<K, V> map = new TreeMap<K, V>();
if (list != null) {
for (V item : list) {
map.put(item.getId(), item);
}
}
return map;
}
Simply define it when you define the generic type:
public static <K, V extends BaseEntity<K>> Map<K, V> entityListToIdMap(..) {
I know, that I can use Raw types to write XMLAdapter, but can I use generic types. I tried reading the API ( link ), but did not even notice a clue about this.
For example map:
I want to use, something like:
#XmlJavaTypeAdapter(GenericMapAdapter<String, Double>.class)//
private final HashMap<String, Double> depWageSum = //
new HashMap<String, Double>();
to get
<depWageSum>
<entry key="RI">289.001</entry>
<entry key="VT">499.817</entry>
<entry key="HI">41.824</entry>
...
<depWageSum>
And class itself would probably look something in the lines of:
#SuppressWarnings("serial") public class GenericMapAdapter<K, V> extends XmlAdapter<GenericMapAdapter.MapType<K, V>, Map<K, V>> {
public static class MapType<K, V> {
#XmlValue protected final List<MapTypeEntry<K, V>> entry = new ArrayList<MapTypeEntry<K, V>>();
public static class MapTypeEntry<K, V> {
#XmlAttribute protected K key;
#XmlValue protected V value;
private MapTypeEntry() {};
public static <K, V> MapTypeEntry<K, V> of(final K k, final V v) {
return new MapTypeEntry<K, V>() {{this.key = k; this.value = v;}};
} } }
#Override public Map<K, V> unmarshal(final GenericMapAdapter.MapType<K, V> v) throws Exception {
return new HashMap<K, V>() {{ for (GenericMapAdapter.MapType.MapTypeEntry<K, V> myEntryType : v.entry)
this.put(myEntryType.key, myEntryType.value);}};
}
#Override public MapType<K, V> marshal(final Map<K, V> v) throws Exception {
return new GenericMapAdapter.MapType<K, V>() {{for (K key : v.keySet())
this.entry.add(MapTypeEntry.of(key, v.get(key)));}};
} }
You will not be able to do this as described. The type parameters will not be retained by the class. However you could introduce some simple subclasses that could leverage the logic from your GenericMapAdapter:
public class StringDoubleMapAdapter extends GenericMapAdapter<String, Double> {
}
Then use the adapter sub class on the property:
#XmlJavaTypeAdapter(StringDoubleMapAdapter.class)//
private final HashMap<String, Double> depWageSum = //
new HashMap<String, Double>();
For more information on XmlAdapter see:
http://bdoughan.blogspot.com/2010/07/xmladapter-jaxbs-secret-weapon.html
One of my favourites from apache commons-collections was the LazyMap which would use a Transformer to instantiate values on the fly when doing map.get(newKey); // Will not return null!.
Why doesn't google collections have the same?
Hey look! It does!
It's called new MapMaker().makeComputingMap(Function<? super K, ? extends V> computer)
Awesome.
Note that map maker is a factory - you can make one, set all the object reference types, expansion properties (and even object expiration time!), and then go about creating lots of computing maps (or other types) with one line calls.
e.g. like pretty much everything else about the google-collections library, it's really good - once you've figured out where 'it' is
since 10.0, guava have a new class CacheBuilder instead, and it's gwt-compatible.
These are the differences.
I suggest to write your own
public class LazyMap<K, V> extends ForwardingMap<K, V> {
final Function<? super K, ? extends V> factory;
final Map<K, V> delegate;
public static <K, V> LazyMap<K, V> lazyMap(final Map<K, V> map, final Supplier<? extends V> supplier) {
return new LazyMap<>(map, supplier);
}
public static <K, V> LazyMap<K, V> lazyMap(final Map<K, V> map, final Function<? super K, ? extends V> factory) {
return new LazyMap<>(map, factory);
}
private LazyMap(final Map<K, V> map, final Function<? super K, ? extends V> factory) {
this.factory = factory;
this.delegate = map;
}
private LazyMap(final Map<K, V> map, final Supplier<? extends V> supplier) {
this.factory = Functions.forSupplier(supplier);
this.delegate = map;
}
#Override
protected Map<K, V> delegate() {
return delegate;
}
#Override
public V get(final Object key) {
if (delegate().containsKey(key) == false) {
#SuppressWarnings("unchecked")
final K castKey = (K) key;
final V value = factory.apply(castKey);
delegate().put(castKey, value);
return value;
}
return delegate().get(key);
}
}