2012-01-27 17 views
5

Analizo el archivo CSV y creo objetos de dominio usando supercsv. Mi objeto de dominio tiene un campo de enumeración, por ejemplo:Enumerando enumeraciones con SuperCSV ICsvBeanReader

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; 
} 
} 

mi enumeración se ve así:

public enum Type { 

    CANCEL, REFUND 
} 

Tratar de crear las habas de este archivo 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); 

esta falla con Error al completar un contexto de objeto: procesador ofensivo nulo: nulo en org.supercsv.io.CsvBeanReader.fillObject (origen desconocido) en org.supercsv.io.CsvBeanReader.read (Fuente desconocida)

¿Alguna pista sobre el análisis de enumeraciones? ¿Debo escribir mi propio procesador para esto?

ya he tratado de escribir mi propio procesador, algo como esto:

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

pero muere con la misma excepción.

El contenido de mi archivo enums.csv es simple:

CANCELAR
REEMBOLSO

+0

que necesita para escribir su propio procesador, no hay Analizador adecuada en supercsv para eso. – oers

+0

ok, es bueno saber que esta es la forma correcta –

+0

editado la pregunta con mis intentos de escribir procesador propio (la primera vez haciendo preguntas sobre el desbordamiento de la pila, por lo que todavía aprender a hacerlo correctamente - tenga paciencia :) –

Respuesta

1

Me trataron de reproducir el error, pero todo funciona para mí. Yo uso 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); 
    } 
+1

Gracias, pero eso no es todo. El valor no es nulo; ya se ha verificado esto con el depurador. La variable "tipo" se asigna con el valor enum correcto. Agregar contenido de enumeraciones a la pregunta. –

+1

@TomekKaczanowski Entonces sospecho que Enum rompe Supercsv en alguna parte :) Debería depurar supercsv para encontrar que:/El src está en el paquete que descargó. – oers

+0

¡Gracias por la ayuda de todos modos! Probablemente use otro bean (con String en vez de enum) y luego cree un constructor de copia en el bean real o algo así. –

7

La excepción que está recibiendo es porque CsvBeanReader no puede crear una instancia de la clase TypeWithEnum, ya que no tiene (sin argumentos) constructor por defecto. Probablemente sea una buena idea imprimir el seguimiento de la pila para que pueda ver todos los detalles de lo que salió mal.

Super CSV se basa en el hecho de que debe haber suministrado un Java bean válido, es decir, una clase con un constructor predeterminado y getters/setters públicos para cada uno de sus campos.

que se puedan solucionar la excepción añadiendo lo siguiente a TypeWithEnum:

public TypeWithEnum(){ 
} 

En cuanto a consejos sobre el análisis enumeraciones las dos opciones más fáciles son:

1. Utilizando el procesador 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. Creación de un CellProcessor personalizado

Crear su procesador

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); 
    } 

} 

Úsalo!

@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()); 
    } 

} 

Estoy trabajando en un próximo lanzamiento de Super CSV.Me aseguraré de actualizar el sitio web para dejar en claro que debe tener un Java Bean válido, y tal vez una descripción de los procesadores disponibles, para aquellos que no estén dispuestos a leer Javadoc.

+0

Alternativamente, podría encadenar dos procesadores 'Token' para obtener el mismo efecto, p. 'final CellProcessor [] processors = new CellProcessor [] {new Token (Type.CANCEL.name(), Type.CANCEL, new Token (Type.REFUND.name(), Type.REFUND));' –

1

Aquí es un procesador celular genérico para las enumeraciones

/** 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); 
    } 

} 

y lo va a usar

new EnumCellProcessor<Type>(Type.class); 
+0

También agregué esto como un parche para SuperCSV y podría llegar hasta la próxima versión. –