Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I store Java types, allowing only some specific ones?

Tags:

java

generics

Lets assume I want to have a class that acts a descriptor for records, where each record has a set of attributes.

Each attribute has a unique name and should have a specific type that corresponds to a certain Java type such as Integer, String, Short, Double, ...

The list of possible types should be restricted such as I support only Integer and String for instance.

private HashMap<String, Class> attributeList = new HashMap<String, Class>();

In the above example the HashMap is a list of attributes where as the key is the attribute name and the value should be the type of the attribute (Integer or String).

What would be the best way to restrict the definition of the value of the Hashmap?

like image 209
Jack Gibson Avatar asked Sep 07 '11 19:09

Jack Gibson


2 Answers

You could of course use wrapper methods to add elements to the map, and do a check for Integer and Sring there. But then you only get runtime errors. I agree with you that restricting the type to get static errors is much better.

For that, I would actually not use Integer.class and String.class, but an enum:

enum Types { String, Integer };

private Map<String, Types> attributeList = new HashMap<String, Types>();

UPDATE:

Come to think of it, there is another (but more complicated) solution, if you have to stick to Class objects: You can use the fake enum pattern, that is use a set of constants (usually the integers 2^i are used) like an enum. So you could define your Class objects as the constants. That of course does not guarantee that no other class objects are put into the map. That's why Joshua Bloch item 30 says "Use enums instead of int constants". But you can then use the Checker Framework to pull an additional type system over your constants using the Fake Enum checker:

@SuppressWarnings("fenum:assignment.type.incompatible")
public class TypeEnum {
  public static final @Fenum("Types") Class INT_CONST = Integer.class;
  public static final @Fenum("Types") Class STR_CONST = String.class;
}

Then you can define your map with a restriction on the type Class:

private HashMap<String, @Fenum("Types") Class> attributeList
   = new HashMap<String, @Fenum("Types") Class>();

Of course, you would need to include the Fenum Checker into your compiler.

like image 89
DaveFar Avatar answered Oct 24 '22 16:10

DaveFar


How about subclass HashMap and override the put method, throwing an exception when an unsupported type is used? (Untested... just off the top of my head.)

class MyAttributes extends HashMap<String, Class> {
    private Set<Class> allowedTypes;

    public MyAttributes() {
        allowedTypes = new HashSet<Class>();
        allowedTypes.add(Integer.class);
    }
    public Class put(String key, Class value) {
        if(!allowedTypes.contains(value)) {
            throw new UnsupportedTypeException(); // <-- Your new exception type.
        }
        return super.put(key, value);
    }
}
like image 24
Stoney Avatar answered Oct 24 '22 17:10

Stoney