0

Recently came upon a case where I want up-front but configurable types (long story). Typically I do this

Type t = new TypeToken<ArrayList<Integer>>() {}.getType();

I would like to place that right hand side into my spring properties file and either issue a call similar to this:

Type t = env.getProperty("type-property");

Or use @ConfigurationProperties.

I typically work with @ConfigurationProperties, but the repo I'm in does not have it available. I could make the case to have dependencies pulled in if the first way simply isn't possible, but the path of least resistance is preferable.

I have tried some variations of the following property definition with angle brackets, parentheses, and square brackets --- none worked out.

type-property=java.util.ArrayList<java.lang.Integer>

I've had a hard time getting anything useful with the kinds of search terms you're forced to use with this problem. I found this related question, but didn't have luck translating it to non-xml configuration (I cannot do xml style in this project either). link: Create a Guava TypeToken in Spring xml config?

EDIT: Using the answer provided by @LppEdd, I used the following calls for de/serialization:

Type sampleType = new TypeToken<HashSet<ArrayList<Integer>>>() {}.getType();
// serialize via java.lang.reflect.Type.getTypeName()
String serializedType = sampleType.getTypeName();
// above string value is "java.util.HashSet<java.util.ArrayList<java.lang.Integer>>"
// deserialize via org.eclipse.jetty.util.TypeUtil.fromName(String name)
Type sampleTypeAgain = TypeUtil.fromName(serializedType);
Kongmingtwo
  • 95
  • 2
  • 7

2 Answers2

0

To answer your "translating to Java" point:

@Bean
@Qualifier("IntegerArrayList")
public Type integerArrayList() {
   return new TypeToken<ArrayList<Integer>>() {}.getType();
}

Usage:

@Autowired
@Qualifier("IntegerArrayList")
private Type type;

Alternatively...

I'll get you started here.
The "better" approach would be to use @ConfigurationProperties with a custom PropertySource implementation. All the Type sub-classes should be serializable, so you can store serialized data and deserialize on the fly.

The fields' names, obviously, would correspond to the Type(s) mapping keys.

class TypePropertySource extends PropertySource<TypeSource> {
    private final TypeSource source;

    TypePropertySource(final TypeSource source) {
        super("a-name", source);
        this.source = source;
    }

    @Override
    public Object getProperty(final String name) {
        try {
            return (Type) source.getAndDeserialize(name);
        } catch (final Exception e) {
            // Recover or do nothing.
        }

        return null;
    }
}

Edit: I really don't know if types other than String are supported for property values in Spring.

LppEdd
  • 20,274
  • 11
  • 84
  • 139
0

Have you considered using Spring SPEL? It almost accomplishes solution for you except due to bad support for generics you need to create separate class for each of your subclass of TypeToken.

For example with concrete class of :

import java.util.ArrayList;
import com.google.common.reflect.TypeToken;

public class MyType extends TypeToken< ArrayList<Integer> >{

}

You can have property like this:

type-property: new com.comcast.viser.ipPreference.web.MyType().getType()

And inject it like this:

@Value("#{${type-property}}")
private java.lang.reflect.Type type;
tsolakp
  • 5,858
  • 1
  • 22
  • 28