How can I put a delayed method execution to the Map? - java

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

Related

Mocking generics and wild card with mockito

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());

Why is a subclass constructor undefined in its parent class?

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!

Scope in higher order functions in Java 8 lambda syntax of Combinator Pattern

I'm trying to understand the syntax in the create method of the following example:
import java.math.BigDecimal;
import java.util.function.Consumer;
import java.util.function.Function;
#FunctionalInterface
interface Before<T, R> extends Function<Consumer<T>, Function<Function<T, R>, Function<T, R>>> {
static <T, R> Before<T, R> create() {
return before -> function -> argument -> {
before.accept(argument);
return function.apply(argument);
};
}
static <T, R> Function<T, R> decorate(Consumer<T> before, Function<T, R> function) {
return Before.<T, R>create().apply(before).apply(function);
}
}
public class BeforeExample {
void demo() {
System.out.println("----------------------------------");
System.out.println("Starting BEFORE combinator demo...");
System.out.println("----------------------------------");
Function<BigDecimal, String> addTax = this::addTax;
Consumer<BigDecimal> before = this::before;
Function<BigDecimal, String> addTaxDecorated = Before.decorate(before, addTax);
BigDecimal argument = new BigDecimal("100");
String result = addTaxDecorated.apply(argument);
System.out.println("Done - Result is " + result);
System.out.println();
}
private void before(BigDecimal argument) {
System.out.println("BEFORE: Argument is " + argument);
}
private String addTax(BigDecimal amount) {
System.out.println("Adding heavy taxes to our poor citizen...");
return "$" + amount.multiply(new BigDecimal("1.22"));
}
}
Can someone please explain:
what is going on in the return before -> function -> argument -> {...} block and how the variables before, function and argument become known without seemingly being passed into create's signature, as well as
what the multiple -> signify.
Thank you.
what is going on in the return before -> function -> argument -> {...}
block and how the variables before, function and argument become known
without seemingly being passed in
The following piece of code can help you understand the block and the usage of variables within:
static <T, R> Before<T, R> create() {
return new Before<T, R>() {
#Override
public Function<Function<T, R>, Function<T, R>> apply(Consumer<T> before) {
return new Function<Function<T, R>, Function<T, R>>() {
#Override
public Function<T, R> apply(Function<T, R> function) {
return new Function<T, R>() {
#Override
public R apply(T argument) {
before.accept(argument);
return function.apply(argument);
}
};
}
};
}
};
}
what the multiple -> signify.
The lambda representation for each of those functional interfaces combined to represent the implementation of create method.

Generic Return type for collections

Is is possible to have a generic return type such that collection can built with interface as well as implementation.
public static void main(String[] args) {
List<Test1> list = ImmutableList.of(new Test1());
List<ITest> test_return_1 = buildIntRange(list);
List<Test1> test_return_2 = buildIntRange(list); //error
}
private static <K extends ITest> List<ITest> buildIntRange(List<K> test) {
return ImmutableList.copyOf(test);
}
Sure. Use the same signature as ImmutableList.copyOf, or just use ImmutableList.copyOf directly:
static <T> List<T> copyOf(Iterable<? extends T> collection)

Cleanest way to create a Guava Multimap from a Java 8 stream

I have a List<Foo> and want a Multimap<String, Foo> where we've grouped the Foo's by their getId() function.
I am using Java 8 and its almost awesome in that you can do:
List<Foo> foos = ...
Map<String, List<Foo>> foosById = foos.stream().collect(groupingBy(Foo::getId));
However, I have a good amount of code that wants a MultiMap<String, Foo> so this doesnt save me anything and I'm back to using a for-loop to create my Multimap. Is there a nice "functional" way that I am missing?
You can just use the Guava Multimaps factory:
ImmutableMultimap<String, Foo> foosById = Multimaps.index(foos, Foo::getId);
or wrap a call to Multimaps.index with a Collector<T, A, R> interface (shown below, in an unoptimized naive implementation).
Multimap<String, Foo> collect = foos.stream()
.collect(MultimapCollector.toMultimap(Foo::getId));
and the Collector:
public class MultimapCollector<T, K, V> implements Collector<T, Multimap<K, V>, Multimap<K, V>> {
private final Function<T, K> keyGetter;
private final Function<T, V> valueGetter;
public MultimapCollector(Function<T, K> keyGetter, Function<T, V> valueGetter) {
this.keyGetter = keyGetter;
this.valueGetter = valueGetter;
}
public static <T, K, V> MultimapCollector<T, K, V> toMultimap(Function<T, K> keyGetter, Function<T, V> valueGetter) {
return new MultimapCollector<>(keyGetter, valueGetter);
}
public static <T, K, V> MultimapCollector<T, K, T> toMultimap(Function<T, K> keyGetter) {
return new MultimapCollector<>(keyGetter, v -> v);
}
#Override
public Supplier<Multimap<K, V>> supplier() {
return ArrayListMultimap::create;
}
#Override
public BiConsumer<Multimap<K, V>, T> accumulator() {
return (map, element) -> map.put(keyGetter.apply(element), valueGetter.apply(element));
}
#Override
public BinaryOperator<Multimap<K, V>> combiner() {
return (map1, map2) -> {
map1.putAll(map2);
return map1;
};
}
#Override
public Function<Multimap<K, V>, Multimap<K, V>> finisher() {
return map -> map;
}
#Override
public Set<Characteristics> characteristics() {
return ImmutableSet.of(Characteristics.IDENTITY_FINISH);
}
}
Guava 21.0 introduced several methods that return Collector instances which will convert a Stream into a Multimap grouped by the result of applying a function to its elements. These methods are:
ImmutableListMultimap.toImmutableListMultimap — creates an ImmutableListMultimap
ImmutableSetMultimap.toImmutableSetMultimap — creates an ImmutableSetMultimap
Multimaps.toMultimap — Creates a Multimap using the given Supplier
ImmutableListMultimap<String, Foo> foosById = foos.stream().collect(
ImmutableListMultimap.toImmutableListMultimap(
Foo::getId, Function.identity()));
ImmutableSetMultimap<String, Foo> foosById = foos.stream().collect(
ImmutableSetMultimap.toImmutableSetMultimap(
Foo::getId, Function.identity()));
HashMultimap<String, Foo> foosById = foos.stream().collect(
Multimaps.toMultimap(
Foo::getId, Function.identity(), HashMultimap::create)
);

Categories

Resources