2012-01-27 12 views
5

Analizzo il file CSV e creo un oggetto dominio utilizzando supercsv. Il mio oggetto di dominio ha un campo enum, ad esempio:Analizzare enumerazioni 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; 
} 
} 

mio enum si presenta così:

public enum Type { 

    CANCEL, REFUND 
} 

Cercando di creare i fagioli di questo file 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); 

questo viene a mancare con Errore durante il riempimento di un contesto oggetto: processore offendente null: null in org.supercsv.io.CsvBeanReader.fillObject (sorgente sconosciuta) su org.supercsv.io.CsvBeanReader.read (sorgente sconosciuta)

Qualche suggerimento sull'analisi delle enumerazioni? Dovrei scrivere il mio processore per questo?

Ho già provato a scrivere il mio proprio processore, qualcosa di simile:

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

ma muore con la stessa eccezione.

Il contenuto del mio file enums.csv è semplice:

ANNULLA
RIMBORSO

+0

è necessario scrivere il proprio processore, non v'è alcuna Parser adatto a supercsv per questo. – oers

+0

ok, bello sapere che questo è il modo giusto –

+0

modificato la domanda con i miei tentativi di scrivere il proprio processore (prima volta ponendo domande sullo stack overflow, così imparo ancora come farlo correttamente - sii paziente :) –

risposta

1

ho cercato di riprodurre l'errore, ma tutto funziona per me. Io 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

Grazie, ma non è quello. Il valore non è nullo - già controllato con debugger. La variabile "tipo" viene assegnata con il giusto valore enum. Aggiungere il contenuto di enumerazioni alla domanda. –

+1

@TomekKaczanowski Quindi sospetto che l'Enum spezzi Supercsv da qualche parte :) Dovresti eseguire il debug di supercsv per scoprire che:/Il src è nel pacchetto che hai scaricato. – oers

+0

Grazie comunque per l'aiuto! Probabilmente userò un altro bean (con String invece di enum) e poi creerò un costruttore di copia sul bean reale o qualcosa del genere. –

7

L'eccezione che stai ricevendo è perché CsvBeanReader non può istanziare la classe TypeWithEnum, in quanto non dispone di un (senza argomenti) costruttore di default. Probabilmente è una buona idea stampare la traccia dello stack in modo da poter vedere tutti i dettagli di ciò che è andato storto.

Super CSV si basa sul fatto che dovresti aver fornito un valido Java bean, cioè una classe con un costruttore predefinito e getter/setter pubblici per ciascuno dei suoi campi.

modo da poter risolvere l'eccezione aggiungendo quanto segue a TypeWithEnum:

public TypeWithEnum(){ 
} 

Per quanto riguarda i suggerimenti su analisi enumerazioni le due opzioni più semplici sono:

1. Utilizzando il processore 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. Creazione di un dispositivo CellProcessore personalizzato

Crea il processore

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

} 

Usalo!

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

} 

Sto lavorando a una prossima versione di Super CSV.Sarò sicuro di aggiornare il sito Web per chiarire che è necessario disporre di un bean Java valido, e forse una descrizione dei processori disponibili, per coloro che non sono inclini a leggere Javadoc.

+0

In alternativa, è possibile collegare due processori 'Token' insieme per lo stesso effetto, ad es. 'finale CellProcessor [] processors = new CellProcessor [] {new Token (Type.CANCEL.name(), Type.CANCEL, new Token (Type.REFUND.name(), Type.REFUND));' –

1

Ecco un processore Cell generico per le enumerazioni

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

} 

e si intende utilizzare

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

Ho anche aggiunto questo come patch per SuperCSV e potrebbe entrare nella prossima versione. –