views:

317

answers:

5

Basically I would like to have some dictionary that is an abstaction over legacy #define directives.

I have an old header file that contains 6000+ defines, that are used as flag parametersome function and these defines denote one type of entity parameter.

In C i have

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

In Java i would like to call

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

And Parameter would encapsulate all logic that is associated with getting the parameter from library.

Parameter instances are automatically extracted from header and converted to java code, but the problem is that Parameter class gets too big - i.e. i get code too large compile error (let me underline: there are more that 6000 parameters).

And I would be thrilled to do this abstraction in a way that enables IDE o use autocompletion, and would wery much dislike idea of storing Parameter objects in say HashMap.

EDIT: Parameter Class is defined in following way:

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);
}
+2  A: 

An obvious hack would be to either partition into a big inheritance chain, or better partition into interfaces (no need for the public static final noise) and one interface to inherit them all.

You could save space by making the creation code smaller. Instead of:

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

A minimalist approach would be:

parameter("NAME T AAB")

For details of limitations, see section 4.10 of the JVM Spec (2nd Ed). To see what your compiled code is like, use javap -c.

Tom Hawtin - tackline
serialized forms are good...
Jason S
I'll try splitting it across couple intercfaces, as you suggested.
jb
A: 

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

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

Jason S
I want to enable IDE autocompletion, which won't work with anything that is not an java object member.
jb
ahhhhhhhhh gotit.
Jason S
+1  A: 

Maybe I'm not understanding what you want to do correctly, but this looks like a perfect 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 version of Java is recent enough (1.5+). They serialize too!

And yes, it works with autocomplete, although a list of 6000 is big.

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

Ex:

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;
    }
}

Now this lets you do the kind of thing you want. Ex:

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

Since they don't change during run-time (after all, #DEFINEs can't), an ENUM should fit the bill.

As for the pure size, it might behoove you do try to catogorize them slightly, and put them in a couple of Enum groups.

This gives you the ability to associate the meta-data (the numbers), do auto complete, ==, and such.

MBCook
Enum was my first approach :) Also generated 'code too large' compile error due to vast amount of values.
jb
Dang. I guess there is a limit. It'd fit the bill pretty nicely if you cut your #DEFINEs into groups, but I realize that's a big refactoring. You could do what you have in your code in the Q, but generate everything at class load in a static block. That's my best guess. You'd lose auto-complete though.
MBCook
Static block has size constraints too . . . i did a static block per parameter ;)
jb
Wow. You're really stuck. You could ignore the static block and do it in groups, using the class as a singleton. This next suggestion is REALLY ridiculous, but some kind of giant C function with a switch statement by JNI? I can't think of anything else but massive refactoring. Sorry.
MBCook
A: 

I think that's what you want. I guess, 'T' is the type and you want to use generics so that the user doesn't have to cast the #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 a parameter just call:

String value = Parameter.NAME.getValue();

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

Andreas_D
The whole problem is that there are too many of that parameters. . . and I get code too large compile error.
jb
A: 

Basically, I think that the multiple interface approach is the way to go. Here's how I would structure that solution; I don't know what the second argument to your Parameter constructor meant, so I've 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);
}

(and so forth)

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

Daniel Martin