UnmodifiableMap with Function<X, Y> values fails to compile - java

I have a reference:
public final static LinkedHashMap<String, Function<OrderBean, String>> DELEGATES;
Which I initialize like:
static {
LinkedHashMap<String, Function<OrderBean, String>> tmp = new LinkedHashMap<>();
tmp.put(OrderCols.FIELD1, OrderBean::getFIELD1);
tmp.put(OrderCols.FIELD2, OrderBean::getFIELD2);
...
DELEGATES = Collections.unmodifiableMap(tmp);
}
On the last line of the static block (the assignment to DELEGATES), I get this compiler error:
Error:(64, 48) java: incompatible types: no instance(s) of type variable(s) K,V exist so that java.util.Map conforms to java.util.LinkedHashMap>
Am I messing something up? Or do unmodifiable views don't like Function types?

No, your issue is that instead of
public final static LinkedHashMap<String, Function<OrderBean, String>> DELEGATES;
you should have
public final static Map<String, Function<OrderBean, String>> DELEGATES;
...because unmodifiableMap returns a bare Map implementation. (The backing data structure will still be a LinkedHashMap, though.)

Related

Hashmap to Function<string, string> to Hashmap?

Currently have code that initializes a Function<String, Object> lookup variable:
Map<String, String> map = new HashMap<>();
...
lookup = map::get;
Is it possible to derive the HashMap from this lookup variable? According to (https://docs.oracle.com/javase/8/docs/api/java/util/function/Function.html) there may not be. Possibly a domain getter and an output getter for Function<String, Object> types?
This might or might not feasible: when Java generate the lambda, it creates an implementation of Function which reference variables used by the lambda as synthetic fields. Since the lambda is map::get, there is a synthetic field for the map.
Using this code and jdoodle, or any java 11 compiler:
import java.util.*;
import java.util.function.*;
import java.lang.reflect.*;
public class MyClass {
public static void main(String args[]) {
Map<String, String> map = new HashMap<>();
Function<String, String> lookup = map::get;
System.out.println(lookup);
System.out.println(lookup.getClass());
for (Field field : lookup.getClass().getDeclaredFields()) {
System.out.println(field);
}
}
}
If you execute the code, you should see a field:
MyClass$$Lambda$1/0x0000000100060c40#4c3e4790
class MyClass$$Lambda$1/0x0000000100060c40
private final java.util.Map MyClass$$Lambda$1/0x0000000100060c40.arg$1
The MyClass$$Lambda$1/0x0000000100060c40.arg$1 is the reference to map.
As you can see, the name is generated and not very easy to predict: you could certainly assume "somewhere" that if there is one field of type Map, then it may be the map used in map::get.
The field is private and with Java 11, you don't know the module of the generated class: you may not even access it using reflection (or java.lang.invoke.MethodHandle).
The short answer is no, it is not reasonably possible. Neither I think you should try to do it unless you want to know how it works.

Java object: Dynamic type not visible

I have the following code:
public class A implements B{
private final Map<String, Map<String, Object>> processors = new ConcurrentHashMap<>();
...
#override(from B)
public void doSomething() {
processors.putIfAbsent(new ConcurentHashMap<>()); ->compilation error
}
The following error is raise:
The method putIfAbsent() is undefined for the type Map<String,Map<String,object>
Can somebody explain to me which is the cause of this error?
You are missing your key when you call putIfAbsent. You are only passing the value (i.e. the map) as an argument.
Also: What is a? Try something like
processors.putIfAbsent("a key", new ConcurrentHashMap<String, Object>());

Meaning of ? in Map<String, ?>

Method createBuilderFactory in javax.json needs argument of type Map<String, ?>
Generally, we have map with like Map<String, String>(some other data types in place of String)
But I didn't understand what does ? stands for. And in order to pass argument of type Map<String, ?>, how I should define the map.
Can someone please help me to understand this better?
In Java generics the ? stands for wildcard, which represent any object.
If you create a method that takes Map<String, ?> you are saying that you expect a Map that maps from String keys to any possible object values:
public static void main(String[] args) {
Map<String, Object> map1 = null;
Map<String, String> map2 = null;
test(map1);
test(map2);
}
private static void test(Map<String, ?> settings) {}
I had difficulties when I need to pass Map<String, ?> to my function, which was accepting Map<String, Object>. And this cut it:
Map<String, ?> mapQuestion = ...
mapObject = (Map<String, Object>)mapQuestion;

How to use a map with a generic enum type as function return type in Java

I am using an interface method that returns the map with these key, values.
public interface IParse<T> {
Map<String, T> parse(); //T is an enum type
}
Now in the implementation classes, I use the function parse with
public class TestClass1 implements IParse
{
public Map<String, EnumType1> parse()
{
Map<String, EnumType1> map1 = new HashMap<>();
// Logic to fill the map
return map1;
}
}
public class TestClass2 implements IParse
{
public Map<String, EnumType2> parse()
{
Map<String, EnumType2> map2 = new HashMap<>();
// Logic to fill the map
return map2;
}
}
and return the map containing appropriate enum type. But eclipse seems does not like it. One of the help options shows "Infer Generic Type Arguments".
Now in the above case, how do I use properly return the map without any type casting. Is there any other way I can use the interface method with a return value a map containing values as enum class types. Please give me an example on how to do this.
Please let me know if any further details are required.

Pass a Map<String, String> to a method requiring Map<String, Object>

I have a method with the following signature
public static ActionDefinition reverse(String action, Map<String, Object> args)
And I have method that returns the following:
public static Map<String, String> toMap(String value)
Is there some way I can cast the output of toMap to be used in reverse, something like:
ActionDefinition ad = reverse("Action.method", toMap("param1=value1,param2=value2"));
I'd need to do something like
(Map<String, Object>) toMap("param1=value1,param2=value2");
but I couldn't fin the way to do it
I also tried with the following method
public static Map<String, String> toMap(String value) {
Map<String, Object> source = toMap(value);
Map<String, String> map = new LinkedHashMap<String, String>();
for(Map.Entry<String, Object> entry: source.entrySet()) {
map.put(entry.getKey(), (String) entry.getValue());
}
return map;
}
but I guess that due to type erasure, I get that the method is duplicated...
any idea?
--
edit
I forgot to state that I can't change reverse method, as many have suggested so far...
if you can change the method you wanna call to
public static ActionDefinition reverse(String action, Map<String, ? extends Object> args)
Change the method signature of reverse to use generics
public static ActionDefinition reverse(String action, Map<String, ? extends Object> args)
Cast it to simple (Map), but beware you are cheating.
You can always cast it to Map because it is one, and you can always feed a raw type into a method because of backwards compatibility, so casting a parametrized type to a raw one is always a way to convert it to any other parameters. But you should only do that when you know that it won't introduce a bug and if you have no sensible alternative.

Categories