The constructor LinkedHashMultimap is not visible - java

The following code doesn't compile
import com.google.common.collect.LinkedHashMultimap;
public class Test {
public static void main(String[] args) {
LinkedHashMultimap<String, String> p = new LinkedHashMultimap<String, String>();
}
}
the error is: The constructor LinkedHashMultimap() is not visible
I have imported the google Java libraries, they are in the build path
and
LinkedHashMultimap<String, String> p;
alone doesn't cause compile error... weird

Use the static create method to get a new instance of LinkedHashMultimap.
LinkedHashMultimap<String, String> p = LinkedHashMultimap.create();

LinkedHashMultimap has no public constructors and the way to get an instance is by using the factory method create. The reason for this is the loophole in Java Generics due to which type inference works only for methods and not for constructors. This means that instead of for example
LinkedHashMultimap<String, Map<String, List<String>>> =
new LinkedHashMultimap<String, Map<String, List<String>>>();
you can write
LinkedHashMultimap<String, Map<String, List<String>>> =
LinkedHashMultimap.create();
With Java 7 the pressure has subsided due to the "diamond operator".

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.

How do I represent complex Map as parameter argument for Class.declaredMethod parameterType?

I have a private method I need to access from a junit. The method has the following signature:
private String search(Map<String, String[]> params, String userName)
I have tried the following setup:
Method mockSearch;
Class[] cArg = new Class[2];
cArg[0] = Map<String, String[]>.class
cArg[1] = String.class;
mockSearch = aClass.getClass().getDeclaredMethod("search", cArg);
Which obviously won't even compile because "cArg[0] = Map<String, String[]>.class" is nonsensical. So I attempted a concrete class for arg 0 like this:
Map<String, String[]> mockMap = new HashMap<>();
cArg[0] = mockMap.getClass();
which threw exception at runtime because of the strictness of the getDeclaredMethod. Here basically is exception snippet:
java.lang.NoSuchMethodException: blah.blah.blah$MyTestClass.search(java.util.HashMap, java.lang.String)
Is there a way to represent a Map<String, String[]> class type that will work? Thanks for ideas.
cArg[0] = Map.class;
You have to use raw class literals with reflection APIs, but there's no risk of ambiguity because you can't have two methods with the same erased signature.

Sonar Error - Make this member "protected"

In the below class I am declaring myMap
public class AllMap {
public static final Map<String, String> myMap= new HashMap<>();
static {
Map.put("yy", "AA");
Map.put("xx", "BB");
}
}
I need to access map in other class.
public class Test {
FieldMap.Map;
}
Everything is working fine,but sonar is giving warning on 1st class:
Make this member "protected".
on the line
public static final Map<String, String> myMap = new HashMap<>();
Should I ignore this warning or should I change it to protected?
If you need to access the map in other classes, then you should protect it against modifications:
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class AllMap {
public static final Map<String, String> myMap;
static {
final Map<String, String> tmpMap = new HashMap<>();
tmpMap.put("yy", "AA");
tmpMap.put("xx", "BB");
myMap = Collections.unmodifiableMap(tmpMap);
}
}
You can still use it and SonarQube won't mark this as error (because the map is read-only).
Read more about Collections#unmodifiableMap(Map).
Sonar is giving you suggestion that your "member" which is:
public final Map<String, String> myMap = new HashMap<>();
should not be public.
Why?
Leaving this as public makes it available from any other package - so you are exposing the member to everybody. Below code is accessing the member directly:
AllMap allMap = new AllMap();
allMap.myMap.put("X", "Y");
In most cases members should be private and accessed by getters and setters, which could prevent with returning the same reference - so you can implement some logic before you get the reference or set it.
If you need to make it static, make static getters and setters.
Sonar lint issue because you are exposing references to mutable objects to client code.Here you are exposing a Map though it is final the final object allows clients to modify the contents of the object.
Never initialize such a field to a client-provided object reference or return the object reference from an accessor.
private static final SomeType [] THE_THINGS = { ... };
public static final List<SomeType> SOMETHINGS =
Collections.unmodifiableList(Arrays.asList(THE_THINGS));
Reference link
Reference link2

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

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