package com.cStruct;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import org.apache.commons.lang.StringUtils;
/**
* 根据注释配置处理C风格的结构体.
* TODO 在处理时的迭代需要优化以提高性能。
* @author licj
*
* @param <T>
*/
public class CStruct<T> {
private List<Field> fields = new ArrayList<Field>();
private String charset;
private Class<T> clazz;
private int byteLength;
/**
* 默认使用utf8编码
* @param clazz
*/
public CStruct(Class<T> clazz)
{
this(clazz, "UTF-8");
}
public CStruct(Class<T> clazz, String charset)
{
this.clazz = clazz;
Collections.addAll(this.fields, clazz.getFields()); //缓存一下
this.charset = charset;
byteLength = calcByteLength();
//这段复制自 Integer.compareTo
Collections.sort(fields, new Comparator<Field>() {
@Override
public int compare(Field o1, Field o2) {
int order1 = getOrder(o1);
int order2 = getOrder(o2);
//这段复制自 Integer.compareTo
return (order1 < order2 ? -1 : (order1 == order2 ? 0 : 1));
}
private int getOrder(Field field)
{
CChar cc = field.getAnnotation(CChar.class);
if (cc != null)
return cc.order();
CBinaryInt cbi = field.getAnnotation(CBinaryInt.class);
if (cbi != null)
return cbi.order();
return 0;
}
});
//TODO 校验设置
}
/**
* @return 计算整个结构体长度
*/
private int calcByteLength()
{
int sum = 0;
for (Field field : fields)
{
if ((field.getModifiers() & Modifier.STATIC) > 0)
continue;
CChar annoChar = field.getAnnotation(CChar.class);
CBinaryInt annoInt = field.getAnnotation(CBinaryInt.class);
if (annoChar != null)
sum += annoChar.value();
else if (annoInt != null)
sum += annoInt.length();
}
return sum;
}
/**
* 生成数据缓冲,并且额外增加指定字节数
* @param source
* @param additionalBytes
*/
public void writeByteBuffer(T source, ByteBuffer buffer)
{
assert source != null;
try
{
for (Field field : fields)
{
if ((field.getModifiers() & Modifier.STATIC) > 0)
continue;
Class<?> type = field.getType();
Object value = field.get(source);
CChar annoChar = field.getAnnotation(CChar.class);
CBinaryInt annoInt = field.getAnnotation(CBinaryInt.class);
if (annoChar != null)
{
String out;
//按字段类型分别处理。优先处理null以及有formatPattern的字段
if (value == null)
out = ""; //所有的null值均用全空格来表示
else if (StringUtils.isNotBlank(annoChar.formatPattern())) //优先考虑pattern,有pattern就使用pattern来格式化了
{
out = MessageFormat.format(annoChar.formatPattern(), value);
}
else if (type.equals(Date.class)) //日期类型
{
if (StringUtils.isNotBlank(annoChar.datePattern())) //日期模版
{
SimpleDateFormat sdf = new SimpleDateFormat(annoChar.datePattern());
out = sdf.format((Date)value);
//这里假定pattern的长度与value()一样,需要在构造函数里设置
}
else
{
out = value.toString(); //接toString,几乎肯定不是要的格式
}
}
else if (type.equals(String.class)) //字符串
{
out = (String)value;
}
else if (Number.class.isAssignableFrom(type) || type == int.class || type == long.class) //数字
{
//转成字符串
//记录符号,只有负数才在最左边加上符号
String sign = "";
if (type.equals(BigDecimal.class))
{
//不输出小数点
BigDecimal bd = (BigDecimal)value;
bd = bd.setScale(annoChar.precision(), annoChar.rounding());
if (bd.signum() == -1)
{
//负数
sign = "-";
bd = bd.abs();
}
out = MessageFormat.format("{0,number,0}", bd.unscaledValue());
}
else
{
//它类型转成long型处理
long num = ((Number)value).longValue();
//long型来判负
if (num < 0)
{
sign = "-";
num = -num;
}
out = MessageFormat.format("{0,number,0}", num);
}
//补完0后再拼符号
if (annoChar.zeroPadding())
{
//这里由于都是数字,所以长度与字节数一样,可以直接leftPad
out = StringUtils.leftPad(out, annoChar.value() - sign.length(), "0");
}
out = sign + out;
}
else
{
//其它类型就直接 toString了
out = value.toString();
}
byte bytes[] = out.getBytes(charset);
if (bytes.length > annoChar.value())
{
buffer.put(bytes, 0, annoChar.value());
}
else
{
if (annoChar.leftPadding())
{
//先输出空格
for (int i = 0; i<annoChar.value() - bytes.length; i++)
buffer.put((byte)' ');
buffer.put(bytes);
}
else
{
//输出内容
buffer.put(bytes);
for (int i = 0; i<annoChar.value() - bytes.length; i++)
buffer.put((byte)' ');
}
}
}
else if (annoInt != null)
{
assert value instanceof Number;
assert annoInt.length() >= 1 && annoInt.length() <= 8 : "二进制字段长度必须在1到8之间";
long l = ((Number)value).longValue();
byte bytes[] = new byte[annoInt.length()];
for (int i=0; i<bytes.length; i++)
bytes[i] = (byte)(l & 0xff);
if (annoInt.bigEndian())
for (int i=bytes.length - 1; i>=0; i--)
buffer.put(bytes[i]);
else
buffer.put(bytes);
}
else
assert false : field.getName() + " 必须指定字段类型注释";
}
}
catch (Exception e)
{
throw new IllegalArgumentException(e);
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public T parseByteBuffer(ByteBuffer buffer)
{
T obj;
try
{
obj = clazz.newInstance();
}
catch (Exception e1)
{
throw new IllegalArgumentException("实例化对象出错,Class:" + clazz.getCanonicalName());
}
for (Field field : fields)
{
try {
if ((field.getModifiers() & Modifier.STATIC) > 0)
continue;
Class<?> type = field.getType();
CChar annoChar = field.getAnnotation(CChar.class);
CBinaryInt annoInt = field.getAnnotation(CBinaryInt.class);
if (annoChar != null)
{
int len = annoChar.value();
byte bytes[] = new byte[len];
buffer.get(bytes);
String value = new String(bytes, charset);
if (StringUtils.isBlank(value) && !annoChar.required() && !type.equals(String.class))
{
//可以忽略的字段,填null
field.set(obj, null);
}
else if (type.equals(Date.class))
{
SimpleDateFormat sdf = new SimpleDateFormat(annoChar.datePattern());
sdf.setLenient(true);
String datePattern = annoChar.datePattern();
if (datePattern.length() < value.length())
{
if (annoChar.leftPadding())
value = StringUtils.right(value, datePattern.length());
else
value = StringUtils.left(value, datePattern.length());
}
field.set(obj, sdf.parse(value));
}
else if (type.equals(String.class))
{
if (annoChar.autoTrim())
value = value.trim();
//字符串直接赋值
field.set(obj, value
没有合适的资源?快使用搜索试试~ 我知道了~
读取文件数据并解析成bean实体类
共16个文件
class:6个
java:5个
project:1个
3星 · 超过75%的资源 需积分: 50 16 下载量 124 浏览量
2015-08-19
15:40:24
上传
评论 1
收藏 278KB ZIP 举报
温馨提示
很多时候需要文件做数据交互,接收到文件后需要对文件解析成bean实体类,这里提供的是工具类,任意文件转任意实体都可以,只要简单的配置一下Class类,很实用
资源推荐
资源详情
资源评论
收起资源包目录
myProject.zip (16个子文件)
myProject
测试数据
testdata 204B
myTest
.project 382B
src
com
cStruct
CChar.java 2KB
CBinaryInt.java 932B
CStruct.java 10KB
test
CStructTest.java 778B
TestData.java 523B
.settings
org.eclipse.jdt.core.prefs 598B
.classpath 367B
bin
com
cStruct
CBinaryInt.class 576B
CStruct$1.class 1KB
CChar.class 861B
CStruct.class 9KB
test
CStructTest.class 2KB
TestData.class 1KB
依赖jar包
commons-lang-2.6.jar 278KB
共 16 条
- 1
资源评论
- Hard_Z2018-10-29你好,demo运行起来没有错了,但是数据还是为空?能留个联系方式吗
wodexzjsn
- 粉丝: 0
- 资源: 1
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功