I have a problem with Java static initialization. What I want to do is some type checking with generic constants and to translate between types and type names. So I have some typed constants in interface MC and a hash map in inner class Type to translate names to types. Now when I call MC.Type.getValue("MInteger") the inner class Type is initialized but not the static constants in the outer class MC so the return value is null. How can I get Java to initialize these constants? I could do
static { Type<?> dummy = MC.MBoolean; }
in class Type but isn't there some better way to do this. Or am I doing this totally wrong.
import java.util.HashMap;
import java.util.Map;
interface MC {
public static final Type<Boolean> MBoolean = new Type<>("MBoolean");
public static final Type<Integer> MInteger = new Type<>("MInteger");
public static class Type<T> {
private static final Map<String, Type<?>> types = new HashMap<>();
private final String name;
private Type(String name) {
this.name = name;
types.put(name, this);
}
public String getName() {
return name;
}
public static Type<?> getValue(String name) {
return types.get(name);
}
}
}
public class Main {
public static void main(String[] args) {
System.out.println(MC.Type.getValue("MInteger"));
MC.MBoolean.getName();
System.out.println(MC.Type.getValue("MInteger"));
}
}
Since all Type instances are included in your MC class, a very direct approach to solving this problem would be to move registration of the class with the Type.types map from the constructor of Type to its static initializer:
private static final Map<String, Type<?>> types = new HashMap<>();
static {
types.put(MBoolean.getName(), MBoolean);
types.put(MInteger.getName(), MInteger);
}
private Type(String name) {
this.name = name;
// removed types.put(name, this); from here
}
Demo.
You can use either static initializer block:
private static final Map<String, Type<?>> types = new HashMap<>();
static {
types.put(MC.MBoolean.getName(), MC.MBoolean);
types.put(MC.MInteger.getName(), MC.MInteger);
}
or double brace initialization:
private static final Map<String, Type<?>> types = new HashMap<>() {{
put(MC.MBoolean.getName(), MC.MBoolean);
put(MC.MInteger.getName(), MC.MInteger);
}};
First curly braces creates new anonymous subclass of HashMap, second curly braces are instance initializer block which is executed at construction time (arg-less constructor for anonymous classes).
The Constructor won't initialize unless you explicitly call MC.MBoolean. so better you go with the Double brace initialization.
private static final Map<String, Type<?>> types = new HashMap<>() {
{
put(MC.MBoolean.getName(), MC.MBoolean);
put(MC.MInteger.getName(), MC.MInteger);
}
};
Related
I have a class with static variable
#Data
public final class Code {
private static Map<String, List<String>> codesForType = new HashMap<String, List<String>>() {{
put("code1", Arrays.asList("AVDF", "WREQ", "AWER"));
put("code2", Arrays.asList("SHYT", "DWEA", "XSSS", "AQWE"));
}};
public static List<String> getCodesByType(String type) {
return codesForType.get(type);
}
}
with following api
#GetMapping("/codes")
public Code getCodeForType() {
return new Code();
}
This is giving exception with message No converter found for return value of type: class com.model.Code.
Tried making the member as public but still has the same issue.
It works when I remove static keyword from private static Map<String, List<String>> codesForType
I could be missing a basic understanding of static keyword.
You don't need to create a new object as your methods are static.
you can simply do this :
#GetMapping("/codes")
public List<String> getCodeForType() {
// replace type with something you will receive in your request.
return Code.getCodesByType(type);
}
Collection type always return 'unknownSymbol' in a custom sonar check rule class.
//demo class
public class SaasConstantNameCheckCase {
private static final long serialVersionUID;
private final String title;
public static final Integer maxSize = 1111;// Noncompliant
private static List list = new ArrayList<>();
private static HashMap<String, String> map = new HashMap<>();
}
// custom rule class
#Override
public void visitVariable(VariableTree tree) {
VariableSymbol symbol = (VariableSymbol) tree.symbol();
String type = symbol.type().name();
System.out.println("type->"+type);
}
// test result
type->long
type->String
type->Integer
type->!unknownSymbol!
type->!unknownSymbol!
Why?
SonarJava will show this unknownSymbol! string when it fails to resolve the actual type symbols.
In this particular case, you should either use fully qualified types java.util.List and java.util.HashMap, or import them.
I have a class
like below
public class SampleReflection {
public static final String TWO_name = "html";
public static final String TWO_find = "css";
public static final String ONE_KEY_java = "java";
public static final String ONE_KEY_jsp = "jsp";
public static final String ONE_KEY_oracle = "oracle";
public static final String ONE_KEY_spring = "spring";
public static final String ONE_KEY_struts = "struts";
}
I would like to get all the fields which starts with ONE_KEY and their value.
because the ONE_KEY_xxx can be of any numbers.
how to do this in java reflection or any other way in java ?
thanks
You can use SampleReflection.class.getDeclaredFields(), iterate over the result and filter by name. Then call field.get(null) to get the value of the static fields. If you want to access non-public fields as well you might have to call first.setAccessible(true) (provided the security manager allows that).
Alternatively you could have a look at Apache Common's reflection utilities, e.g. FieldUtils and the like.
Depending on what you actually want to achieve there might be better approaches though, e.g. using a map, enums etc.
In your case where you have static fields using an enum might be a better way to go.
Example:
enum SampleFields {
TWO_name("html"),
TWO_find("css"),
ONE_KEY_java("java"),
ONE_KEY_jsp("jsp");
ONE_KEY_oracle("oracle"),
...;
private String value;
private SampleFields(String v) {
value = v;
}
}
Then iterate over SampleFields.values() and filter by name.
Alternatively, if that fits your needs, you could split the names and pass a map to the enum values, e.g.
enum SampleFields {
TWO(/*build a map "name"->"html","find"->"css")*/ ),
ONE_KEY(/*build a map "java"->"java","jsp"->"jsp", ...*/);
private Map<String, String> values;
private SampleFields(Map<String, String> map) {
values = map;
}
}
Then get the enum values like this: SampleFields.valueOf("ONE_KEY").get("java")
Thanks for the answer,
this is what i was looking for,
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class SampleReflection {
public static final String TWO_name = "html";
public static final String TWO_find = "css";
public static final String ONE_KEY_java = "java";
public static final String ONE_KEY_jsp = "jsp";
public static final String ONE_KEY_oracle = "oracle";
public static final String ONE_KEY_spring = "spring";
public static final String ONE_KEY_struts = "struts";
public static void main(String[] args) {
Class<?> thisClass = null;
Map<String,String> keyValueMap = new HashMap<String,String>();
try {
thisClass = Class.forName(SampleReflection.class.getName());
Field[] aClassFields = thisClass.getDeclaredFields();
for(Field f : aClassFields){
String fName = f.getName();
if(fName.contains("ONE_KEY")){
keyValueMap.put(fName, (String)f.get(SampleReflection.class));
}
}
for (Map.Entry<String, String> entry : keyValueMap.entrySet())
{
System.out.println(entry.getKey() + "=" + entry.getValue());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
I had a static class that contained several static variables:
public class A{
static {
}
public static final String param1= "paramVal1";
public static final String param2= "paramVal2";
}
I want to change the code, so that the variables will be in a map:
public class A{
static {
}
private static Map<String, String> params = new HashMap<String, String>() ;
public static void initParams() {
params.put("param1", paramVal1);
params.put("param2", paramVal2);
}
However, I already have many classes that call those public parameters, and I don't want to go to every class and change it. Is there any way to use some define function, that would cause java to return the map's value, when the parameter is called? i.e if someone calls A.param1, it would return params.get("param1")
A parameter in not as easy to use (and overwrite) than a method. So I think that short answer to your question is no. That's one of the reasons of getters and setters. But you can allways do the inverse, that is keep the old parameters for compatibility and use a map for newer uses :
public class A{
static {
param1 = "paramVal1";
param2 = "paramVal2";
params = new HashMap<String, String>;
params.put("param1", param1);
params.put("param2", param2);
// eventually other inits for params
}
public static final String param1= "paramVal1";
public static final String param2= "paramVal2";
public static Map<String, String params;
/* or better private static Map<String,String> params
and access via getter */
public static getParam(String name) {
return param.get(name);
}
}
That way, old classes could allways do A.param1, and for newer classes you could start using A.get("param1").
You can do this:
public class A {
private static Map<String, String> params = new HashMap<String, String>();
static {
params.put("param1", "paramVal1");
params.put("param2", "paramVal2");
}
public static final String param1 = params.get("param1");
public static final String param2 = params.get("param2");
}
Is there any way to define static final variables (effectively constants) in a Java enum declaration?
What I want is to define in one place the string literal value for the BAR(1...n) values:
#RequiredArgsConstructor
public enum MyEnum {
BAR1(BAR_VALUE),
FOO("Foo"),
BAR2(BAR_VALUE),
...,
BARn(BAR_VALUE);
private static final String BAR_VALUE = "Bar";
#Getter
private final String value;
}
I got the following error message for the code above: Cannot reference a field before it is defined.
As IntelliJ IDEA suggest when extracting constant - make static nested class. This approach works:
#RequiredArgsConstructor
public enum MyEnum {
BAR1(Constants.BAR_VALUE),
FOO("Foo"),
BAR2(Constants.BAR_VALUE),
...,
BARn(Constants.BAR_VALUE);
#Getter
private final String value;
private static class Constants {
public static final String BAR_VALUE = "BAR";
}
}
public enum MyEnum {
BAR1(MyEnum.BAR_VALUE);
public static final String BAR_VALUE = "Bar";
works fine
public enum MyEnum {
// BAR1( foo), // error: illegal forward reference
// BAR2(MyEnum.foo2), // error: illegal forward reference
BAR3(MyEnum.foo); // no error
public static final int foo =0;
public static int foo2=0;
MyEnum(int i) {}
public static void main(String[] args) { System.out.println("ok");}
}
This can be done without an inner class for the constant.
Maybe you should considering breaking this enum into two fields: an enum and an int:
#RequiredArgsConstructor
public enum MyEnum {
BAR("Bar"),
FOO("Foo")
#Getter
private final String value;
}
And then use:
private MyEnum type;
private int value;
(You can put that into a class or not, whether it makes sense to you)