我有一个基本上可以处理配置类型转换的方法,但是在指定泛型类型(例如List
)时,它成为如何处理特定类型的问题。在理想的世界中,例如使用类型见证程序:
List<String> someVal = MyConfig.SOME_VAL.<List<String>>.as(List.class);'
(完整as
代码):
/**
* Attempts to return the {@link Config} value as a casted type. If the
* value cannot be casted it will attempt to return the default value. If
* the default value is inappropriate for the class, the method will
* throw a {@link ClassCastException}.
*
* @since 0.1.0
* @version 0.1.0
*
* @param <T> The type of the casting class
* @param c The class type to cast to
* @return A casted value, or {@code null} if unable to cast. If the passed
* class parameter is of a primitive type or autoboxed primitive,
* then a casted value of -1 is returned, or {@code false} for
* booleans. If the passed class parameter is for {@link String},
* then {@link Object#toString()} is called on the value instead
*/
default public <T> T as(Class<T> c) {
Validate.notNull(c, "Cannot cast to null");
Validate.isTrue(Primitives.unwrap(c) != void.class, "Cannot cast to a void type");
Object o = this.get();
if (o == null) {
T back = Reflections.defaultPrimitiveValue(c);
if (back != null) { //catch for non-primitive classes
return back;
}
}
if (c == String.class) {
return (T) String.valueOf(o);
}
if (c.isInstance(o)) {
return c.cast(o);
}
if (c.isInstance(this.getDefault())) {
return c.cast(this.getDefault());
}
throw new ClassCastException("Unable to cast config value");
}
因此,从本质上讲,这剩下两部分的问题:为什么不能将见证人类型用于类的泛型(例如List(raw)
-> List<String>
),以及如何在不做多余的转换的情况下支持使用泛型边界检索类?第一点特别让我感到困惑,因为这是完全合法的:
List<String> test = new ArrayList<>();
test = MyConfig.FRIENDLY_MOBS.as(test.getClass());
尽管返回了原始类型的列表
该行确实是邪恶的(类型擦除/原始类型),因为没有检查任何Collection类型是否真正包含字符串。
test = MyConfig.FRIENDLY_MOBS.as(test.getClass());
我认为最简单的解决方案是编写一个as方法,该方法同时使用集合类型和元素类的类对象。请参见以下示例(在静态范围内,因此必须对其进行调整):
static List<String> words = Arrays.asList("Hello", "Bonjour", "engine");
static public <E, Coll extends Collection<E>> Coll as(Class<? extends Collection> collClass, Class<E> elemClass) {
if (collClass.isInstance(words)) {
Collection coll = collClass.cast(words);
for (Object o : coll)
if (!elemClass.isInstance(o))
throw new ClassCastException("BAM");
return (Coll)coll;
}
return null;
}
现在发现以下行为:
final List<String> list = as(List.class, String.class); // works
final List<String> list = as(List.class, Integer.class); // compile error: type check
final List<Integer> list = as(List.class, String.class); // compile error: type check
final List<Integer> list = as(List.class, Integer.class); // ClassCastException
至于其他尝试:iirc Jackson正在进行一些神奇的TypeToken东西,这些东西可以捕获诸如List <String>之类的类型。我认为它滥用了Enum <T>
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句