2014-10-07 4 views
1

После неудачной попытки использовать TypeTools Resolving generic type information with TypeTools Вместо этого я пытаюсь использовать https://github.com/cowtowncoder/java-classmate.Устранение типичного типа с одноклассником java

Может кто-нибудь помочь мне исправить этот код?

public T fromMap(S map) { 
    TypeResolver typeResolver = new TypeResolver();   
    ResolvedType type = typeResolver.resolve((new MapperImpl<T, S>() {}).getClass()); 
    List<ResolvedType> params = type.typeParametersFor(MapperImpl.class); 
    ResolvedType typeT = params.get(0); 

    ObjectMapper objectMapper = new ObjectMapper(); 
    T obj = objectMapper.convertValue(map, (Class<T>) typeT.getErasedType()); 
    return obj; 

} 

Я получаю эту ошибку:

java.util.LinkedHashMap cannot be cast to LoginInputMapTest$Foo java.lang.ClassCastException at shouldMapToFoo(LoginInputMapTest.java:83)

с этим минимальным теста:

public static class Foo { 
     private String a; 

     public String getA() { 
      return a; 
     } 

     public void setA(String a) { 
      this.a = a; 
     } 

    } 

    @Test 
    public void shouldMapToFoo() { 
     Map<String, Object> map = new HashMap<>(); 
     map.put("a", "aaa"); 

     Mapper<Foo, Map<String, Object>> mapper = new MapperImpl<>(); 
     Foo foo = mapper.fromMap(map); 
     Assert.assertEquals(foo.getA(), map.get("a")); 
    } 
+0

Делает ли ваш MapperImpl что-то? Похоже, вы создали анонимный класс, фактически не обращаясь к нему. Или это просто аббревиатура? –

+0

Анонимный класс предназначен для предоставления подтипа. Я думаю, вам нужно это, чтобы разрешить общий тип. См. Этот пример: https://github.com/cowtowncoder/java-classmate#resolving-type-parameters-for-a-class – dmz73

ответ

2

Там нет ничего, что вы можете сделать в вашем методе fromMap, чтобы получить аргумент типа при условии, что было привязаны к вашей переменной типа T.

Я предлагаю вам создать реализацию Mapper специально для Foo.

class FooMapperImpl<S> implements Mapper<Foo, S> { 
    public Foo fromMap(S map) { 
     ObjectMapper objectMapper = new ObjectMapper(); 
     Foo obj = objectMapper 
       .convertValue(map, Foo.class); 
     return obj; 
    } 
} 

(Хотя я не понимаю, почему вам нужен тип источника S, если он всегда будет Map.)

+0

Вы правы, нет необходимости параметризовать интерфейс Mapper с помощью S. Почему вы говорите я ничего не могу сделать, чтобы получить тип Т. Не это ли назначение библиотек типа TypeTools и classmate? – dmz73

+0

То, что я пытаюсь сделать, это именно то, что они описывают здесь, в «4. Использование в реальном мире» http://www.cowtowncoder.com/blog/archives/2012/04/entry_471.html – dmz73

+0

@ dmz73 Это кажется совершенно другим. Они могут извлекать тип из 'handler'. Но ваш метод 'fromMap' не имеет ничего, что можно использовать для извлечения аргумента типа, предоставленного для' T'. –

0

Мне кажется, что вы не в полной мере понять способ Java универсальные типы работают, в отношении переменных типа (T, S). Хорошее место, чтобы узнать более подробно об этом:

http://www.angelikalanger.com/GenericsFAQ/FAQSections/ParameterizedTypes.html

, но в основном переменные типа не несут никакой информации во время выполнения общего типа. Поэтому, когда вы номинально называете метод с определенной параметризацией, ничего не происходит, если вы не передадите фактический Class экземпляр, подходящий параметризованный. Таким образом, ваш метод компилируется в байткод немного больше, чем:

public Object fromMap(Object map) { ... } 

Теперь, если вы передаете Map в map, тип выполнения будет просто Map.class и нет никаких параметров типа указано: значения Java не имеют какой-либо тип выполнения параметризации. Базовый класс одинаковый между, скажем, Map<String,Number> и Map<UUID,byte[]>. Объявления параметров влияют только на компилятор Java, который добавляет необходимые приведения, чтобы обеспечить правильное использование типов значений.

У нас нет библиотек, которые есть у вас, к сожалению. Поэтому использование, которое вы предлагаете, невозможно реализовать как есть.

Это не означает, что вы не можете передать ввод, но это означает, что он должен быть передан извне. С основным Джексоном, у вас есть TypeReference вы можете использовать:

new TypeReference<Map<KeyType, ValueType>>() { }; 

бы построить ссылку на тип Map<KeyType,ValueType>. Или вы можете построить их программно, используя TypeFactory; что-то вроде:

mapper.getTypeFactory().constructMapType(Map.class, KeyType.class, ValueType.class); 
// or with recursively constructing nested generic types 

Сейчас: ClassMate может, наоборот, тип извлечения информации из определений классов. Если у вас есть класс с полями, методы, которые используют объявление общего типа, трудно легко определить объявленную параметризацию. Но это не похоже на то, что вы действительно хотите или нуждаетесь здесь.Скорее вы сможете построить его, используя функциональность манипуляции типа Джексона.

Смежные вопросы