Click or drag to resize

Type Literals

Because DME Component Libraries was originally developed for the .NET Framework, some subsystems require runtime use of the types of generic parameters. However, since Java implements its generics using type erasure, this information is not available from the JVM itself, so this information must be stored in your application code directly.

One common approach to this problem is to use Class objects to store this information. For example:

Java
public static <T> boolean isT(Object obj, Class<T> klass) {
    return klass.isInstance(obj);
}

Java
Object obj = "a string";

boolean isString = isT(obj, String.class);
// => true
boolean isInteger = isT(obj, Integer.class);
// => false

However, this approach has some limitations. Class literals can only be created for raw types, that is, it is impossible to write Map<String, List<String>>.class, or List<T>.class. To avoid this, DME Component Libraries uses special objects called TypeLiterals to capture information about the full type at the point where it is specified, based on a technique described by Neal Gafter, and an implementation by Gunni Rode.

How does it work? Consider this example:

Java
public static <T> boolean isT(Object obj, TypeLiteral<T> typeLiteral) {
    // for simplicity this only checks the raw type. More complicated
    // techniques can be used to check the full type.
    return typeLiteral.asClass().isInstance(obj);
}

Java
Object obj = "a string";

boolean isString = isT(obj, new TypeLiteral<String>() {});
// => true

boolean isMapOfIntegerToDouble = isT(obj, new TypeLiteral<Map<Integer, Double>>() {});
// => false

To construct a TypeLiteral, you simply construct an anonymous inner subclass of TypeLiteral, parameterized on the type you need to capture.

The following example uses TypeLiteral in the context of DME Component Libraries, specifically with the ScalarBitErrorRate type from the Communications Library.

Java
Scalar scalarBpsk = new ScalarBitErrorRate<>(new TypeLiteral<ModulationBpsk>() {});
Scalar scalarBpsk2 = new ScalarBitErrorRate<>(new TypeLiteral<ModulationBpsk>() {});
Scalar scalarQpsk = new ScalarBitErrorRate<>(new TypeLiteral<ModulationQpsk>() {});

boolean result1 = scalarBpsk.isSameDefinition(scalarBpsk2);
// => true
boolean result2 = scalarBpsk.isSameDefinition(scalarQpsk);
// => false