Разбор перечислений с помощью SuperCSV ICsvBeanReader - PullRequest
5 голосов
/ 27 января 2012

Я анализирую файл CSV и создаю объекты домена, используя supercsv .Мой объект домена имеет одно поле перечисления, например:

public class TypeWithEnum {

private Type type;

public TypeWithEnum(Type type) {
    this.type = type;
}

public Type getType() {
    return type;
}

public void setType(Type type) {
    this.type = type;
}
}

Моё перечисление выглядит так:

public enum Type {

    CANCEL, REFUND
}

Попытка создать bean-компоненты из этого файла CSV:

final String[] header = new String[]{ "type"  };
ICsvBeanReader inFile = new CsvBeanReader(new FileReader(
    getFilePath(this.getClass(), "learning/enums.csv")), CsvPreference.STANDARD_PREFERENCE);

final CellProcessor[] processors = 
    new CellProcessor[]{ TODO WHAT TO PUT HERE? };
TypeWithEnum myEnum = inFile.read(
    TypeWithEnum.class, header, processors);

эта ошибка завершается с ошибкой при заполнении контекста объекта: нулевой нарушающий процессор: нулевой в org.supercsv.io.CsvBeanReader.fillObject (неизвестный источник) в org.supercsv.io.CsvBeanReader.read (неизвестный источник)1013 * Любой намек на синтаксический анализ перечислений?Должен ли я написать свой собственный процессор для этого?

Я уже пытался написать свой собственный процессор, что-то вроде этого:

class MyCellProcessor extends CellProcessorAdaptor {
    public Object execute(Object value, CSVContext context) {
        Type type = Type.valueOf(value.toString());
        return next.execute(type, context);
    }
}

, но он умирает с тем же исключением.

Содержимое моего файла enums.csv простое:

ОТМЕНА
ВОЗВРАТ

Ответы [ 3 ]

7 голосов
/ 21 февраля 2012

Исключение, которое вы получаете, заключается в том, что CsvBeanReader не может создать экземпляр вашего класса TypeWithEnum, поскольку у него нет конструктора по умолчанию (без аргументов).Вероятно, это хорошая идея - напечатать трассировку стека, чтобы вы могли увидеть полную информацию о том, что пошло не так.

Super CSV основан на том факте, что вы должны были предоставить действительный Java bean т.е. класс с конструктором по умолчанию и общедоступными методами получения / установки для каждого из его полей.

Таким образом, вы можете исправить исключение, добавив следующее к TypeWithEnum:

public TypeWithEnum(){
}

Что касаетсяПодсказки при разборе перечислений имеют два самых простых варианта:

1.Использование процессора HashMapper

@Test
public void hashMapperTest() throws Exception {

    // two lines of input
    String input = "CANCEL\nREFUND";

    // you could also put the header in the CSV file
    // and use inFile.getCSVHeader(true)
    final String[] header = new String[] { "type" };

    // map from enum name to enum
    final Map<Object, Object> typeMap = new HashMap<Object, Object>();
    for( Type t : Type.values() ) {
        typeMap.put(t.name(), t);
    }

    // HashMapper will convert from the enum name to the enum
    final CellProcessor[] processors = 
        new CellProcessor[] { new HashMapper(typeMap) };

    ICsvBeanReader inFile = 
        new CsvBeanReader(new StringReader(input),
        CsvPreference.STANDARD_PREFERENCE);

    TypeWithEnum myEnum;
    while((myEnum = inFile.read(TypeWithEnum.class, header, processors)) !=null){
        System.out.println(myEnum.getType());
    }

}

2.Создание собственного CellProcessor

Создайте свой процессор

package org.supercsv;

import org.supercsv.cellprocessor.CellProcessorAdaptor;
import org.supercsv.cellprocessor.ift.CellProcessor;
import org.supercsv.exception.SuperCSVException;
import org.supercsv.util.CSVContext;

public class TypeProcessor extends CellProcessorAdaptor {

    public TypeProcessor() {
        super();
    }

    public TypeProcessor(CellProcessor next) {
        super(next);
    }

    public Object execute(Object value, CSVContext context) {

        if (!(value instanceof String)){
            throw new SuperCSVException("input should be a String!");
        }

        // parse the String to a Type
        Type type = Type.valueOf((String) value);

        // execute the next processor in the chain
        return next.execute(type, context);
    }

}

Используйте его!

@Test
public void customProcessorTest() throws Exception {

    // two lines of input
    String input = "CANCEL\nREFUND";

    final String[] header = new String[] { "type" };

    // HashMapper will convert from the enum name to the enum
    final CellProcessor[] processors = 
        new CellProcessor[] { new TypeProcessor() };

    ICsvBeanReader inFile = 
        new CsvBeanReader(new StringReader(input),
        CsvPreference.STANDARD_PREFERENCE);
    TypeWithEnum myEnum;
    while((myEnum = inFile.read(TypeWithEnum.class, header, processors)) !=null){
        System.out.println(myEnum.getType());
    }

}

Я работаю над предстоящим выпуском Super CSV.Я обязательно обновлю веб-сайт, чтобы было ясно, что у вас должен быть действительный компонент Java - и, возможно, описание доступных процессоров, для тех, кто не склонен читать Javadoc.

1 голос
/ 15 ноября 2013

Вот базовый процессор ячейки для перечислений

/** A cell processor to convert strings to enums. */
public class EnumCellProcessor<T extends Enum<T>> implements CellProcessor {

    private Class<T> enumClass;
    private boolean ignoreCase;

    /**
     * @param enumClass the enum class used for conversion
     */
    public EnumCellProcessor(Class<T> enumClass) {
        this.enumClass = enumClass;
    }

    /**
     * @param enumClass the enum class used for conversion
     * @param ignoreCase if true, the conversion is made case insensitive
     */
    public EnumCellProcessor(Class<T> enumClass, boolean ignoreCase) {
        this.enumClass = enumClass;
        this.ignoreCase = ignoreCase;
    }

    @Override
    public Object execute(Object value, CsvContext context) {
        if (value == null)
            return null;

        String valueAsStr = value.toString();

        for (T s : enumClass.getEnumConstants()) {
            if (ignoreCase ? s.name().equalsIgnoreCase(valueAsStr) : s.name().equals(valueAsStr)) {
                return s;
            }
        }

        throw new SuperCsvCellProcessorException(valueAsStr + " cannot be converted to enum " + enumClass.getName(), context, this);
    }

}

, и вы будете использовать его

new EnumCellProcessor<Type>(Type.class);
1 голос
/ 27 января 2012

Я пытался воспроизвести вашу ошибку, но у меня все работает. Я использую SuperCSV 1.52:

  private enum ENUMS_VALUES{TEST1, TEST2, TEST3};
  @Test
  public void testEnum3() throws IOException
  {
    String testInput = new String("TEST1\nTEST2\nTEST3");
    ICsvBeanReader  reader = new CsvBeanReader(new StringReader(testInput), CsvPreference.EXCEL_NORTH_EUROPE_PREFERENCE);
    final String[] header = new String[] {"header"};
    reader.read(this.getClass(), header, new CellProcessor[] {new CellProcessorAdaptor() {

      @Override
      public Object execute(Object pValue, CSVContext pContext)
      {
        return next.execute(ENUMS_VALUES.valueOf((String)pValue), pContext);
      }}});

  }

  @Test
  public void testEnum4() throws IOException
  {
    String testInput = new String("TEST1\nTEST2\nTEST3");
    ICsvBeanReader reader = new CsvBeanReader(new StringReader(testInput), CsvPreference.EXCEL_NORTH_EUROPE_PREFERENCE);
    final String[] header = new String[] {"header"};
    reader.read(this.getClass(), header, new CellProcessor[] {new CellProcessorAdaptor()
    {

      @Override
      public Object execute(Object pValue, CSVContext pContext)
      {
        return ENUMS_VALUES.valueOf((String)pValue);
      }}});
  }

  public void setHeader(ENUMS_VALUES value)
  {
    System.out.println(value);
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...