1

Моим вариантом было написать универсальный трансформатор CSV, который должен иметь возможность конвертировать любую строку Java POJO в CSV.Написание генерического трансформатора POJO на CSV

Моя реализация:

public <T> List<String> convertToString(List<T> objectList) { 

     List<String> stringList = new ArrayList<>(); 
     char delimiter = ','; 
     char quote = '"'; 
     String lineSep = "\n"; 

     CsvMapper mapper = new CsvMapper(); 
     CsvSchema schema = mapper.schemaFor(!HOW_TO!); 

     for (T object : objectList) { 

      try { 
       String csv = mapper.writer(schema 
         .withColumnSeparator(delimiter) 
         .withQuoteChar(quote) 
         .withLineSeparator(lineSep)).writeValueAsString(object); 

      } catch (JsonProcessingException e) { 

       System.out.println(e); 
      } 
     } 

     return stringList; 
} 

Я использовал Джексон-DataFormat-Csv библиотеку, но я застрял с HOW_TO! part, ie Как извлечь .класс объекта из objectList. Я учился и наткнулся на Type Erasure. Поэтому я думаю, что это не так просто, как дать параметр .class в качестве моей функции. Но я также извлекаю этот список объектов из общего объекта с использованием Java Reflection, поэтому у меня нет возможности предоставить параметры .class.

Есть ли обходной путь для этого?

ИЛИ

Любые другие подходы/библиотеки, где я могу преобразовать общий List<T> objectList to List<String> csvList с функциональностью добавления разделителей, кавычки, линейные разделители и т.д.

Спасибо!

ответ

1

Существует простой вариант. Я добавил несколько строк кода, чтобы показать:

public <T> List<String> convertToString(List<T> objectList) { 

    if(objectList.isEmpty()) 
     return Collections.emptyList(); 

    T entry = objectList.get(0); 

    List<String> stringList = new ArrayList<>(); 
    char delimiter = ','; 
    char quote = '"'; 
    String lineSep = "\n"; 

    CsvMapper mapper = new CsvMapper(); 
    CsvSchema schema = mapper.schemaFor(entry.getClass()); 

    for (T object : objectList) { 

     try { 
      String csv = mapper.writer(schema 
        .withColumnSeparator(delimiter) 
        .withQuoteChar(quote) 
        .withLineSeparator(lineSep)).writeValueAsString(object); 

      stringList.add(csv); 
     } catch (JsonProcessingException e) { 
      System.out.println(e); 
     } 
    } 

    return stringList; 
} 

Хитрость заключается в том, чтобы получить один из элементов списка. Чтобы избежать сбоев, я добавил вначале небольшой тест целостности данных, который возвращает неизменяемый пустой список в случае отсутствия элементов в списке ввода. Затем вы извлекаете экземпляр своего объекта и используете его для получения класса.

В качестве альтернативы, если метод ConvertToString в параметризованным классе вы можете сделать это в несколько иначе

public class GenericClass<T> { 

private final Class<T> type; 

public GenericClass(Class<T> type) { 
     this.type = type; 
} 

public Class<T> getMyType() { 
    return this.type; 
} 
} 

Это решение позволяет получить класс T. Я не думаю, что вам нужно это для этого вопроса, но это может пригодиться.

+0

И если первый элемент списка является подклассом, не разделяемым другими элементами списка? –

+0

Это не важно. Это список, он известен в списке, так как это суперкласс. Если ему понадобился обработчик для обработки подклассов, решение будет таким же простым.Просто заново создайте схему в цикле for и сделайте один и тот же getClass для каждого элемента. В своем примере он установил свою схему из цикла, поэтому я предположил, что все элементы списка должны обрабатываться одинаково. Поэтому нет необходимости в особых случаях –

+0

Да, это имеет значение. Учитывая «Список », желая обрабатывать все элементы одинаково, «Class» необходим «MyBaseClass». Но если элемент нуль указывает на экземпляр, тип выполнения которого является 'SubclassA', тогда ваш метод убедит его, что у него есть« Список », и он быстро попадет в неприятности, если все остальные экземпляры также не относятся к этому подкласс. Ваше утверждение «известно по списку как суперкласс» неверно. Тип ссылки в списке - «Объект»; тип среды выполнения является фактическим типом подкласса. Он известен только как базовый класс во время компиляции. –

0

Кажется, эта проблема сложнее, чем большинство людей хотели бы, чтобы это было результатом того, как Java генерирует дженерики. Ответ Бруно показывает варианты, которые могут работать, если вы можете сделать определенные предположения или можете структурировать свой код определенным образом.

Другой вариант, который должен работать в вашем случае может быть найден путем ответов на этот другой вопрос: How to get a class instance of generics type T

В там вы найдете ссылку на статью: http://blog.xebia.com/acessing-generic-types-at-runtime-in-java/

В данном разделе описывается, как для использования ParameterizedType суперкласса объекта. Вы можете применить это к своему объекту List и, надеюсь, он будет работать на вас. Это может, к счастью, работать в этом случае, потому что вы принимаете в качестве параметра объект с суперклассом, параметры которого соответствуют тому, что вам нужно.

В общем, мы не можем полагаться на знание параметров типа во время выполнения. Мы можем в лучшем случае использовать токены типа (параметр типа Class<T>)

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