例如,如果我有一个CSV
这样的文件:
name, age, height
joe, 23, 180.5
我需要一个Blah.java
bean文件自动生成如下:
public class Blah{
String name;
int age;
float height;
// getters and setters...
}
是否有可以实现这一目标的图书馆?我当然搜索过,但空手而归。
答案 0 :(得分:3)
我不知道现有的库能够做到这一点(我没有进行网络搜索,因为很可能,你在提问之前已经这样做了)。
(编辑:似乎在bchetty链接的答案中使用的库至少接近你一直在寻找的那个)
对于最简单的情况,这是通过几行代码完成的 - 尽管严格来说,根本不可能:从CSV文件中,您无法获得任何代码有关列的类型的信息。 (在下面的示例中,我通过手动指定列的类型来解决此问题。)
此外,在许多情况下,写一个简单的"很容易。解决方案,但在第一次拍摄后,需求得到了扩展,事实证明,从一开始就使用复杂的解决方案将是有益的。因此,如果您稍后要将其扩展为
Person
包含Address
对象作为属性)PropertyChangeSupport
)那么您应该考虑使用允许您描述类的基础结构。我现在正在考虑类似Eclipse JDT之类的东西,当然,对于目前的问题,这将是一种过度杀伤力。
编辑2:根据评论,使用一些代码扩展了代码片段""推断""列的类型。请注意,这是一种非常简单实用的方法,它不会进行复杂的错误检查,并且在某些情况下结果可能不是所需的结果。例如。当一列包含第一行中的字符串
100
时,列类型将推断为int
,尽管在第二行中,同一列可以包含字符串123.456
,应该被视为double
- 不要谈论缺失或特殊的价值观,例如比如-
意思是"没有可用数据"。如果某些内容无法根据第一行无法推断为int
或double
,则会将其视为String
。
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class BeanGenerator
{
public static void main(String[] args) throws IOException
{
//testManualSetup();
testAutomaticSetup();
}
private static void testManualSetup()
{
List<BeanProperty> beanProperties =
new ArrayList<BeanProperty>();
beanProperties.add(new BeanProperty("name", String.class));
beanProperties.add(new BeanProperty("age", Integer.TYPE));
beanProperties.add(new BeanProperty("height", Double.TYPE));
String result = generateBeanFile("Person", "", beanProperties);
System.out.println(result);
}
private static void testAutomaticSetup() throws IOException
{
List<BeanProperty> beanProperties = inferBeanProperties("test.csv");
System.out.println("Inferred properties:");
for (BeanProperty beanProperty : beanProperties)
{
System.out.println(beanProperty);
}
String result = generateBeanFile("Person", "", beanProperties);
System.out.println(result);
}
static List<BeanProperty> inferBeanProperties(String fileName) throws IOException
{
FileInputStream fileInputStream = null;
try
{
fileInputStream = new FileInputStream(fileName);
return inferBeanProperties(fileInputStream);
}
finally
{
if (fileInputStream != null)
{
fileInputStream.close();
}
}
}
private static List<BeanProperty> inferBeanProperties(
InputStream inputStream) throws IOException
{
final String delimiter = ",";
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
List<String> names = null;
List<Class<?>> types = null;
while (true)
{
String line = br.readLine();
if (line == null)
{
return Collections.emptyList();
}
if (line.trim().length()==0)
{
continue;
}
if (names == null)
{
names = tokenize(line, delimiter);
}
else
{
types = inferTypes(line, delimiter);
break;
}
}
List<BeanProperty> beanProperties = new ArrayList<BeanProperty>();
for (int i=0; i<names.size(); i++)
{
String name = names.get(i);
Class<?> type = types.get(i);
BeanProperty beanProperty = new BeanProperty(name, type);
beanProperties.add(beanProperty);
}
return beanProperties;
}
private static List<String> tokenize(String line, String delimiter)
{
List<String> list = new ArrayList<String>();
String tokens[] = line.split(delimiter);
for (String token : tokens)
{
list.add(token.trim());
}
return list;
}
private static List<Class<?>> inferTypes(String line, String delimiter)
{
List<String> tokens = tokenize(line, delimiter);
List<Class<?>> types = new ArrayList<Class<?>>();
for (String token : tokens)
{
types.add(inferType(token));
}
return types;
}
private static Class<?> inferType(String token)
{
try
{
Integer.parseInt(token);
return Integer.TYPE;
}
catch (NumberFormatException e)
{
// Ignored
}
try
{
Double.parseDouble(token);
return Double.TYPE;
}
catch (NumberFormatException e)
{
// Ignored
}
return String.class;
}
static class BeanProperty
{
private final String name;
private final Class<?> type;
BeanProperty(String name, Class<?> type)
{
this.name = name;
this.type = type;
}
String getName()
{
return name;
}
Class<?> getType()
{
return type;
}
@Override
public String toString()
{
return name+": "+type;
}
}
static String generateBeanFile(String beanName,
String header,
List<BeanProperty> beanProperties)
{
StringBuilder sb = new StringBuilder();
sb.append(header);
sb.append("public class "+beanName+"\n");
sb.append("{"+"\n");
for (BeanProperty beanProperty : beanProperties)
{
sb.append(" private ");
sb.append(beanProperty.getType().getSimpleName());
sb.append(" ");
sb.append(decapitalize(beanProperty.getName()));
sb.append(";"+"\n");
}
sb.append("\n");
sb.append(" public "+beanName+"()"+"\n");
sb.append(" {"+"\n");
sb.append(" // Default constructor"+"\n");
sb.append(" }"+"\n");
for (BeanProperty beanProperty : beanProperties)
{
sb.append("\n");
sb.append(createSetterString(beanProperty));
sb.append("\n");
sb.append(createGetterString(beanProperty));
}
sb.append("}"+"\n");
return sb.toString();
}
private static String createSetterString(BeanProperty beanProperty)
{
StringBuilder sb = new StringBuilder();
sb.append(" public void set");
sb.append(capitalize(beanProperty.getName()));
sb.append("(");
sb.append(beanProperty.getType().getSimpleName());
sb.append(" ");
sb.append(decapitalize(beanProperty.getName()));
sb.append(")"+"\n");
sb.append(" {"+"\n");
sb.append(" this.");
sb.append(decapitalize(beanProperty.getName()));
sb.append(" = ");
sb.append(decapitalize(beanProperty.getName()));
sb.append(";"+"\n");
sb.append(" }"+"\n");
return sb.toString();
}
private static String createGetterString(BeanProperty beanProperty)
{
StringBuilder sb = new StringBuilder();
sb.append(" public ");
sb.append(beanProperty.getType().getSimpleName());
sb.append(" get");
sb.append(capitalize(beanProperty.getName()));
sb.append("()"+"\n");
sb.append(" {"+"\n");
sb.append(" return ");
sb.append(decapitalize(beanProperty.getName()));
sb.append(";"+"\n");
sb.append(" }"+"\n");
return sb.toString();
}
private static String decapitalize(String s)
{
char c = Character.toLowerCase(s.charAt(0));
return c + s.substring(1);
}
private static String capitalize(String s)
{
char c = Character.toUpperCase(s.charAt(0));
return c + s.substring(1);
}
}
答案 1 :(得分:2)
您可以使用Apache-Commons-CSV来解析CSV文件,然后使用use CGLIB to generate Java class files at runtime。
答案 2 :(得分:-1)
虽然到目前为止我还没有使用它,但是SuperCSV [你已经在你的标签中有了]]有2个自定义bean读取器。 CsvBeanReader and CsvDozerBeanReader。请参阅以下网站上的sample。
/**
* An example of reading using CsvBeanReader.
*/
private static void readWithCsvBeanReader() throws Exception {
ICsvBeanReader beanReader = null;
try {
beanReader = new CsvBeanReader(new FileReader(CSV_FILENAME), CsvPreference.STANDARD_PREFERENCE);
// the header elements are used to map the values to the bean (names must match)
final String[] header = beanReader.getHeader(true);
final CellProcessor[] processors = getProcessors();
CustomerBean customer;
while( (customer = beanReader.read(CustomerBean.class, header, processors)) != null ) {
System.out.println(String.format("lineNo=%s, rowNo=%s, customer=%s", beanReader.getLineNumber(),
beanReader.getRowNumber(), customer));
}
}
finally {
if( beanReader != null ) {
beanReader.close();
}
}
}
<强>更新强>
请注意,您无法创建java类本身,因为您需要知道它从文件中读取的POJO。如果您需要实际创建类文件,您可能需要考虑使用CsvListReader来读取行,然后使用getter和setter手动生成类。但是,您可能需要包含其他元数据,例如&#34;字段类型&#34;。