Итак, приступим к написанию reader-а:
/**
* @author vie
*
* TSVReader.java
* Class for read tab separated values files
*/
public class TSVReader<T> {
private final String filePath;
public TSVReader(String filePath) {
this.filePath = filePath;
}
/**
* This method reads tab separated values file
* into object of the arbitrary class
*
* @param clazz type of transmitted class
* @return List
* @throws com.site.tsv.exceptions.TSVException
*/
public List<T> read(Class<T> clazz) throws TSVException {
List<T> result = new LinkedList<T>();
try {
BufferedReader bReader = new BufferedReader(new FileReader(filePath));
String line;
//recieving all lines
int i = 1;
while ((line = bReader.readLine()) != null) {
//recieving all line members
String datavalue[] = line.split("\t");
//create instance of line entity
Constructor constructor = clazz.getConstructor(null);
Object somethingInstance = constructor.newInstance(null);
//parsing line entity members
Field[] fields = clazz.getDeclaredFields();
//recieve map of line entity member types
Map<Integer, Class<?>> mapFields = defineFields(clazz);
//for each line entity field
if (fields != null && datavalue != null && fields.length == datavalue.length) {
for (int j = 0; j < fields.length; j++) {
//for each line entity field
String s = fields[j].getName();
s = s.substring(0, 1).toUpperCase() + s.substring(1, s.length());
//exec line entity setter methods
Method method = clazz.getMethod("set" + s, mapFields.get(j));
method.invoke(somethingInstance, getDeterminatedValue(datavalue[j], fields[j].getType()));
}
} else if (fields != null && datavalue != null && fields.length != datavalue.length) {
throw new TSVInvalidFileException("Count of formatted file fields on line " + i + " not equal count of entity fields");
}
i++;
result.add((T) somethingInstance);
}
bReader.close();
} catch (FileNotFoundException e) {
throw new TSVException(e);
} catch (IOException e) {
throw new TSVException(e);
} catch (ParseException e) {
throw new TSVInvalidFileException(e);
} catch (NumberFormatException e) {
throw new TSVInvalidFileException(e);
} catch (NoSuchMethodException e) { //reflect
throw new TSVException(e);
} catch (InstantiationException e) {
throw new TSVException(e);
} catch (IllegalAccessException e) {
throw new TSVException(e);
} catch (InvocationTargetException e) {
throw new TSVException(e);
}
return result;
}
/**
* Returns field names and types
*
* @param clazz type of transmitted class
* @return Map<string,integer>.
* @throws com.site.tsv.exceptions.TSVIncorrectAnnotatedFieldsException
*/
private Map<Integer, Class<?>> defineFields(Class<?> clazz) throws TSVIncorrectAnnotatedFieldsException {
Map<Integer, Class<?>> map = new HashMap<Integer, Class<?>>();
Field[] fields = clazz.getDeclaredFields();
int i = 0;
for (Field field : fields) {
if (field.isAnnotationPresent(TSVInteger.class)) {
map.put(i++, Integer.class);
} else if (field.isAnnotationPresent(TSVDouble.class)) {
map.put(i++, Double.class);
} else if (field.isAnnotationPresent(TSVString.class)) {
map.put(i++, String.class);
} else if (field.isAnnotationPresent(TSVDate.class)) {
map.put(i++, Date.class);
}
}
if (fields.length == 0 || fields.length != map.size()) {
throw new TSVIncorrectAnnotatedFieldsException("Some field not annotated or count of fields = 0!");
}
return map;
}
/**
* Returns converted to the native type field
*
* @param original value of obtained field
* @param needType type of transmitted class
* @return Object
* @throws java.text.ParseException
*/
private Object getDeterminatedValue(String original, Class<?> needType) throws ParseException {
if (needType.getName().equals("java.lang.Integer")) {
return Integer.parseInt(original);
} else if (needType.getName().equals("java.lang.Double")) {
return Double.parseDouble(original);
} else if (needType.getName().equals("java.lang.String")) {
return original;
} else if (needType.getName().equals("java.util.Date")) {
SimpleDateFormat formatter = new SimpleDateFormat("dd.MM.yyyy");
return formatter.parse(original);
} else {
return null;
}
}
}
В классе я использовал generics, чтобы проверять заданного типы entity на этапе компиляции. В преобразовании строк с различными типами данных в entity объект мне помог reflection. Для разбора с его помощью entity, написаны приведенные ниже аннотации. Также я создал несколько исключений, чтобы в при выпадении ошибок можно было быстро понять что свалилось, будь то reflection, IO или преобразование чисел и дат.теперь Writer:
/**
* @author vie
*
* TSVWriter.java
* Class for write tab separated values files
*/
public class TSVWriter<T> {
private final static String tab = "\t";
private final String filePath;
public TSVWriter(String filePath) {
this.filePath = filePath;
}
/**
* This method writes tab separated values file
* from entity object
*
* @param list list of line entity objects
* @param clazz type of transmitted class
* @throws com.site.tsv.exceptions.TSVException
*/
public void write(List<T> list, Class<T> clazz) throws TSVException {
try {
BufferedWriter bufferWriter = new BufferedWriter(new FileWriter(filePath));
//getting all line object fields
Field[] fields = clazz.getDeclaredFields();
//for each line
if (fields != null) {
for (T lineObject: list) {
StringBuilder line = new StringBuilder();
//for each line entity field
for (Field field : fields) {
String s = field.getName();
s = s.substring(0, 1).toUpperCase() + s.substring(1, s.length());
//exec line entity setter methods
Method method = clazz.getMethod("get" + s);
String val = method.invoke(lineObject) + "";
line.append(val).append(tab);
}
bufferWriter.write(line.substring(0, line.length() - 1));
bufferWriter.newLine();
}
}
bufferWriter.close();
} catch (FileNotFoundException e) {
throw new TSVException(e);
} catch (IOException e) {
throw new TSVException(e);
} catch (NoSuchMethodException e) {
throw new TSVException(e);
} catch (IllegalAccessException e) {
throw new TSVException(e);
} catch (InvocationTargetException e) {
throw new TSVException(e);
}
}
}
Аннотации:
/**
* @author vie
*/
@Target(value = ElementType.FIELD)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface TSVInteger {
}
/**
* @author vie
*/
@Target(value = ElementType.FIELD)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface TSVDouble {
}
/**
* @author vie
*/
@Target(value = ElementType.FIELD)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface TSVString {
}
/**
* @author vie
*/
@Target(value = ElementType.FIELD)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface TSVDate {
}
Исключения:
/**
* @author vie
*/
public class TSVException extends Exception {
public TSVException() {
super();
}
public TSVException(String message) {
super(message);
}
public TSVException(String message, Throwable cause) {
super(message, cause);
}
public TSVException(Throwable cause) {
super(cause);
}
}
/**
* @author vie
*/
public class TSVInvalidFileException extends TSVException {
public TSVInvalidFileException() {
super();
}
public TSVInvalidFileException(String message) {
super(message);
}
public TSVInvalidFileException(String message, Throwable cause) {
super(message, cause);
}
public TSVInvalidFileException(Throwable cause) {
super(cause);
}
}
/**
* @author vie
*/
public class TSVIncorrectAnnotatedFieldsException extends TSVException {
public TSVIncorrectAnnotatedFieldsException() {
super();
}
public TSVIncorrectAnnotatedFieldsException(String message) {
super(message);
}
public TSVIncorrectAnnotatedFieldsException(String message, Throwable cause) {
super(message, cause);
}
public TSVIncorrectAnnotatedFieldsException(Throwable cause) {
super(cause);
}
}
Все, теперь можно попробовать загрузить и записать в другой файл. Для этого создадим entity, аналогичный структуре файла:
test1 55 01.01.2010 rw test2 daswqrg 56 31.01.2011 comment1 test3 dds 57 30.11.2011 comment32
entity:
/**
* @author vie
*/
public class TestLineEntity {
@TSVString
protected String value;
@TSVInteger
protected Integer id;
@TSVDate
protected Date date;
@TSVString
protected String comment;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
/*other getters and setters*/
}
сам код считывания и записи данных:
TSVReader<TestLineEntity> tsvReader = new TSVReader<TestLineEntity>("test.tsv");
List<TestLineEntity> test = tsvReader.read(TestLineEntity.class);
TSVWriter<TestLineEntity> tsvWriter = new TSVWriter<TestLineEntity>("new_test.tsv");
tsvWriter.write(forum, TestLineEntity.class);
Комментариев нет:
Отправить комментарий