An elegant way to store a large static dictionary with a dictionary in java - or avoid too much code

Basically, I would like to have a dictionary that is an abstraction over deprecated directives #define

.

I have an old header file that contains 6000+ that are used as a flag parameterization function and they define the designation of one type of object parameter

.

In C i

  GetParameter(... , T_CTITLE, ...); 

      

In Java, I would like to call

  Connector.getParameter(Parameter.CTITLE, ...); 

      

And the parameter will encapsulate all the logic associated with getting the parameter from the library.

Parameter instances are automatically extracted from the header and converted to java code, but the problem is that the Parameter class is getting too large - that is, I get a code too large

compilation error (let me stress: there are over 6000 parameters).

And I would love this abstraction in a way that allows the IDE to use autocomplete, and I would hate the idea of ​​storing Parameter objects in say HashMap

.

EDIT: The parameters class is defined like this:

public Parameter{
    /** logic **/
    public static final Parameter<T> parameter1 = new Parameter<T>("NAME", "T", 0xAAB);
    ...
    public static final Parameter<T> parameter6000 = new Parameter<T>("FOO", "T", 0xZZZ);
}

      

0


a source to share


5 answers


The obvious hack would be to either split up into a large inheritance chain, or better split into interfaces (no noise needed public static final

) and one interface to inherit them all.

You can save space by reducing the creation code. Instead:

new Parameter<T>("NAME", "T", 0xAAB)

      



Minimalist approach:

parameter("NAME T AAB")

      

See section 4.10 of the JVM Specification (2nd ed.) For more information on restrictions . To see what your compiled code looks like, use .javap

-c

+4


a source


I may not understand what you want to do right, but this looks like an ideal use for an Enum to me. Since you can add functions to Enums, they should be able to do what you want, as long as your Java version is fairly recent (1.5+). They are serialized too!

And yes, it works with autocomplete, although the list of 6000 is large.

I don't know if there is a limit to the size of an Enum, but you can find out.

Example:

public enum Parameter {
    NAME("Pending", "T", 0xAAB), FOO("Foo", "T", 0x1FC);

    private final String displayValue;
    private final char myChar;
    private final int someNum;

    private Parameter(String display, char c, int num) {
        this.displayValue = display;
        this.myChar = c;
        this.someNum = num;
    }

    public String getDisplayValue() {
        return displayValue;
    }

    public char getMyChar() {
        return myChar;
    }

    public int getSomeNum() {
        return someNum;
    }
}

      



This now allows you to do what you want. Example:

System.out.println("Hi, the value is " + Parameter.NAME.getSomeNum());

      

Since they don't change at runtime (after all, #DEFINEs can't), ENUM must match the count.

As for sheer size, you might try to revoke them a bit, and put them in a couple of Enum groups.

This gives you the ability to bind metadata (numbers), do auto-completion, ==, etc.

+1


a source


Basically, I think a multi-interface approach is the way to go. This is how I would structure this solution; I don't know what the second argument of your Parameter constructor means, so I ignored it.

In ... / com / yourcompany / legacydefines / Parameter.java:

package com.yourcompany.legacydefines;

public class Parameter<T> {
  private final String name;
  private final T val;

  private Parameter(String name, T val) {
    this.val = val;
    this.name = name;
  }

  public static <T> Parameter<T> newParameter(String name, T val) {
    return new Parameter<T>(name, val);
  }

  // then, standard getters for "name" and "val"
}

      

In ... / com / yourcompany / legacydefines / Parameters1.java:

package com.yourcompany.legacydefines;

import static com.yourcompany.legacydefines.Parameter.newParameter;

interface Parameters1 {
  public static Parameter<String> Parameter0001 = newParameter("ABC", "ABCVAL");
  // ...
  public static Parameter<Integer> Parameter0999 = newParameter("FOO", 0xABCD);
}

      

In ... / com / yourcompany / legacydefines / Parameters2.java:

package com.yourcompany.legacydefines;

import static com.yourcompany.legacydefines.Parameter.newParameter;

interface Parameters2 {
  public static Parameter<String> Parameter1001 = newParameter("DEF", "DEFVAL");
  // ...
  public static Parameter<Integer> Parameter1999 = newParameter("BAR", 0x1002);
}

      

(etc.)

In ... / com / yourcompany / legacydefines / Parameters.java:

package com.yourcompany.legacydefines;

interface Parameters extends Parameters1, Parameters2, Parameters3, Parameters4,
                             Parameters5, Parameters6, Parameters7 {}

      

Then in your other code just use Parameters.Parameter4562

+1


a source


expanding on Tom Hawtin's post, consider using JSON to encode a structure.

Or better yet, rather than hard-coding the parameters in your Java code, put them in an XML or JSON file (or properties file) that gets sucked into whatever JAR file you end up creating.

0


a source


I think what you want. I am assuming "T" is a type and you want to use generics so that the user doesn't have to enter #define values:

public class Parameter<T> {

    public final static Parameter<String> NAME = new Parameter<String>("hello");
    // .. 5998 more declarations
    public final static Parameter<Integer> FOO = new Parameter<Integer>(0xff0b);


    private T value;
    private Parameter(T value) {
        this.value = value;
    }
    public T getValue() {
        return value;
    }   
}

      

To access the parameter you just called:

String value = Parameter.NAME.getValue();

      

The java constant is equal to the #defines name, the generic type reflects the type, so we only need to pass the value to the constructor. Code termination stops :)

0


a source







All Articles