2014-04-06 42 views
0

我有一個簡單的POJO,它裏面有一個Map。CellProcessor for MapEntry

public class Product { 
    public Map map; 
} 

然後我的CSV看起來是這樣的:

"mapEntry1","mapEntry2","mapEntry3" 

所以我創建了一個自定義的Cell處理器用於解析那些:

public class MapEntryCellProcessor { 
    public Object execute(Object val, CsvContext context) { 
     return next.execute(new AbstractMap.SimpleEntry<>("somekey", val), context); 
    } 
} 

,然後我在產品中添加一個條目setter方法:

public void setName(Entry<String, String> entry) { 
    if (getName() == null) { 
     name = new HashMap<>(); 
    } 
    name.put(entry.getKey(), entry.getValue()); 
} 

不幸的是,這個我我有2個setter方法:一個接受一個地圖,另一個接受一個並不真正爲我工作的條目(我無法控制POJO如何生成)。有沒有其他的方式可以解析這樣的CSV文件,並且只有在我的產品中接受Map的setter?

回答

1

可以編寫一個單元處理器,將每列收集到一張地圖中。例如,以下處理器允許您指定要添加到的鍵和地圖。

package org.supercsv.example; 

import java.util.Map; 

import org.supercsv.cellprocessor.CellProcessorAdaptor; 
import org.supercsv.cellprocessor.ift.CellProcessor; 
import org.supercsv.util.CsvContext; 

public class MapCollector extends CellProcessorAdaptor { 

    private String key; 

    private Map<String, String> map; 

    public MapCollector(String key, Map<String, String> map){ 
     this.key = key; 
     this.map = map; 
    } 

    public MapCollector(String key, Map<String, String> map, 
     CellProcessor next){ 
     super(next); 
     this.key = key; 
     this.map = map; 
    } 

    public Object execute(Object value, CsvContext context) { 
     validateInputNotNull(value, context); 
     map.put(key, String.valueOf(value)); 
     return next.execute(map, context); 
    } 

} 

然後假設你的產品bean擁有Map<String,String>類型的字段name,你可以按如下方式使用處理器。

package org.supercsv.example; 

import java.io.IOException; 
import java.io.StringReader; 
import java.util.HashMap; 
import java.util.Map; 

import junit.framework.TestCase; 

import org.supercsv.cellprocessor.ift.CellProcessor; 
import org.supercsv.io.CsvBeanReader; 
import org.supercsv.io.ICsvBeanReader; 
import org.supercsv.prefs.CsvPreference; 

public class MapCollectorTest extends TestCase { 

    private static final String CSV = "John,L,Smith\n" + 
     "Sally,P,Jones"; 

    public void testMapCollector() throws IOException{ 
     ICsvBeanReader reader = new CsvBeanReader(
     new StringReader(CSV), 
      CsvPreference.STANDARD_PREFERENCE); 

     // only need to map the field once, so use nulls 
     String[] nameMapping = new String[]{"name", null, null}; 

     // create processors for each row (otherwise every bean 
     // will contain the same map!) 
     Product product; 
     while ((product = reader.read(Product.class, 
      nameMapping, createProcessors())) != null){ 
      System.out.println(product.getName()); 
     } 
    } 

    private static CellProcessor[] createProcessors() { 
     Map<String, String> nameMap = new HashMap<String, String>(); 
     final CellProcessor[] processors = new CellProcessor[]{ 
       new MapCollector("name1", nameMap), 
       new MapCollector("name2", nameMap), 
       new MapCollector("name3", nameMap)}; 
     return processors; 
    } 

} 

此輸出:

{name3=Smith, name2=L, name1=John} 
{name3=Jones, name2=P, name1=Sally} 

你會發現,雖然處理器上的所有3列執行,它只是(在nameMapping陣列因此空值)映射到bean一次。

我還創建了處理器,每個一行讀取時間,否則每個bean將使用同一張地圖......這可能不是你想要的東西;)

+0

謝謝您的回答, 我會試一試,雖然我的第一印象是爲每一行創建單元處理器將顯着降低性能..我有一些CSV超過10000行... –

+0

你認爲這將是確定的,如果CsvContext也暴露了這一行迄今爲止已處理的內容以及當前標題值的名稱。在這種情況下,我可以像這樣創建一個CsvProcessor: 'if(csvContext.getLineSoFar(csvContext.getCurrentHeader())!= null){csvContext.getLineSoFar()。put(STRING,STRING); } else { new HashMap (); } ' –