Обобщения Java и супер-токены - PullRequest
3 голосов
/ 08 марта 2012

Я пытаюсь объединить три следующих метода в одно общее решение, я попробовал несколько идей, которые компилируются, но не очень хорошо во время выполнения.

public static List<User> parseToUsers(HttpResponse response) {
  ObjectMapper mapper = new ObjectMapper();
  String results = parseToString(response);
  return mapper.readValue(results, new TypeReference<List<User>>() {});
}

public static List<Record> parseToRecords(HttpResponse response) {
  ObjectMapper mapper = new ObjectMapper();
  String results = parseToString(response);
  return mapper.readValue(results, new TypeReference<List<Record>>() {});
}

public static Record parseToRecord(HttpResponse response) {
  ObjectMapper mapper = new ObjectMapper();
  String results = parseToString(response);
  return mapper.readValue(results, new TypeReference<Record>() {});;
}

Я также пытался понять это сообщение в блоге о Супер Типовых Жетонах .

EDIT:

Вот что я придумал:

public static <T> T parseJsonResponse(TypeReference<T> type, HttpResponse response) throws DroidException {
    ObjectMapper mapper = new ObjectMapper();
    String results = parseResponseToString(response);
    return readValue = mapper.readValue(results, type);
}

Тогда я называю это так.

parseJsonResponseToList(new TypeReference<List<Record>>() {}, response)

Не совсем удовлетворительно. Есть ли лучшее решение?

Ответы [ 4 ]

2 голосов
/ 08 марта 2012

Так в чем именно проблема? Чем тебе это не нравится?

У Джексона есть другие способы конструирования универсальных типов; так что, возможно, то, что вы ищете, это:

public List<T> listOf(String json, Class<T> elementType) {
   ObjectMapper mapper = new ObjectMapper(); // should (re)use static instance for perf!
   JavaType listType = mapper.getTypeFactory().constructCollectionType(ArrayList.class, elementType);
   return mapper.readValue(json, listType);
}

TypeFactory может использоваться для программного конструирования типов, использующих обобщенные типы - тип возвращаемого значения JavaType, поскольку базовая Java Class стирается по типу. TypeFactory фактически используется для преобразования TypeReference в JavaType и для внутреннего использования.

EDIT

Что касается обычных типов, не относящихся к Коллекции / Карте, это действительно довольно просто:

public T parseSingle(Class<T> cls, InputStream src) throws IOException {
  return mapper.readValue(src, cls);
}

(вы также НЕ хотите читать содержимое как String - оно не только медленно, но и легко портит кодировки символов, поэтому, если возможно, введите InputStream или byte[] вместо)

0 голосов
/ 09 марта 2012

ОК после появления ошибки компиляции:

параметры типа Т не могут быть определены; Не существует уникального максимального экземпляра для переменной типа T с верхними границами T, java.lang.Object

Я ухожу из сеанса сверхинжиниринга и делаю его простым

private static TypeReference<List<Record>>  RECORDS = new TypeReference<List<Record>>() {};

public static <T> T readJson(TypeReference<T> type, String text) {
    ObjectMapper mapper = new ObjectMapper();
    return readValue = mapper.readValue(text, type);
}

используйте это так

readJson(RECORDS, text);

нет перечислений, я просто использую статические поля для TypeReference, и каждый может легко прочитать код, не понимая TypeReference

спасибо, ребята, я кое-что узнал о сегодняшней инженерии: P

0 голосов
/ 08 марта 2012

Хорошо, это мое любимое решение, вдохновленное Dolda2000, я оставляю как есть в своем первоначальном посте и добавляю enum.

public enum TypeRef {
    RECORDS(new TypeReference<List<Record>>() {}), USERS(new TypeReference<List<User>>() {}), USER(new TypeReference<User>() {});

    private TypeReference<?>    type;

    private TypeRef(TypeReference<?> type) {
        this.type = type;
    }

    public TypeReference<?> getType() {
        return this.type;
    }
}

, а затем вместо:

readJsonResponse(new TypeReference<List<Record>>() {}, response)

я могу написать:

readJsonResponse(TypeRef.RECORDS, response);

никакой магии не происходит, но она мне нравится больше, чем упаковка в другом интерфейсе

0 голосов
/ 08 марта 2012

Я действительно не знаю, чем занимаются ваши ObjectMapper и TypeReference классы, так что, возможно, этот ответ вам не очень подходит, но вот как бы я это сделал, если бы вообще понял вашу ситуацию :

public interface Parser<T> {
    public T parse(String results);
    public static class MapperParser<T> implements Parser<T> {
        private final TypeReference<T> type;
        public MapperParser(TypeReference<T> type) {this.type = type;}
        public T parse(String results) {
            return(new ObjectMapper().readValue(results, type));
        }
    }
    public static final Parser<List<User>> users = new MapperParser(new TypeReference<List<User>>());
    public static final Parser<List<Record>> records = new MapperParser(new TypeReference<List<Record>>());
    public static final Parser<Record> record = new MapperParser(new TypeReference<Record>());
}

/* And then, in the class you were in your question: */
public static <T> T parseJsonResponse(Parser<T> parser, HttpResponse response) {
    return(parser.parse(parseResponseToString(response)));
}

Тогда вы можете назвать это так:

parseJsonResponse(Parser.users, response)

Это тебе больше нравится?

...