注解xmlPath实现bean的映射

一、背景

xml文档节点比较多,结构层次复杂,而无需根据xml结构映射实体和取所有的节点内容(一两百个节点,只需取二十多个节点信息)。

二、实现思路

把xmlpath通用注释映射对应的字段。通过反射读取xmlPath,根据xmlPath读取xml文档对应节点内容后反射设值。

三、代码实现

1、缓存字段与xmlpath映射

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * 缓存解析过的xmlField
 *
 */
public class XmlFieldBeanFactory {
	

	private final static ConcurrentMap<Class<?>, Map<Field,XmlField>> xmlTypeMap = new ConcurrentHashMap<Class<?>,Map<Field,XmlField>>();
	
	public static Map<Field,XmlField> getForClass(Class<?> type){
		Map<Field,XmlField> xmlType = xmlTypeMap.get(type);
		if(xmlType == null) {
			xmlType = getXmlType(type);
			xmlTypeMap.put(type, xmlType);
		}
		return xmlType;
	}
	
	private static Map<Field,XmlField> getXmlType(Class<?> type){
		
		Map<Field,XmlField> xmlType = new HashMap<>();
		while (type != null) {//当父类为null的时候说明到达了最上层的父类(Object类).
		      for (Field field : type .getDeclaredFields()) {  
		    	  if(field.isAnnotationPresent(XmlField.class)){//判断成员变量是否有注解
		    		  xmlType.put(field, field.getAnnotation(XmlField.class));
		    	  }
		    	 }
		      type = type.getSuperclass(); //得到父类,然后赋给自己
		}

		return xmlType;
	}
	
}

 

2、根据xmlPath获取body值或属性值

import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.dom4j.Document;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;


/**
 * xml path 映射
 *
 */
public class XmlPathUtil {
	
	
	/**
	 * xml字符串转换Object
	 * @param xml
	 * @param clz 转换对象class
	 * @return
	 * @throws Exception
	 */
	public static <T> T convert(String xml,Class<T> clz) throws Exception{
		InputStream in = null;
		try {
			in = IOUtils.toInputStream(xml);
			return convert(in,clz);
		}finally {
			IOUtils.closeQuietly(in);
		}
	}
	
	/**
	 * xml字符串转换Object
	 * @param xml xml字符串
	 * @param clz 转换对象class
	 * @param ns 命名空间
	 * @param alisa 别名
	 * @return
	 * @throws Exception
	 */
	public static <T> T convert(String xml,Class<T> clz,String ns,String alisa) throws Exception{
		InputStream in = null;
		try {
			in = IOUtils.toInputStream(xml);
			return convert(in,clz,ns,alisa);
		}finally {
			IOUtils.closeQuietly(in);
		}
	}
	
	/**
	 * inputStream xml转Object
	 * @param in
	 * @param clz
	 * @return
	 * @throws Exception
	 */
	public static <T> T convert(InputStream in,Class<T> clz) throws Exception {
			Document doc = new SAXReader().read(in);
			return convert(doc,clz);
	}
	
	/**
	 * inputStream xml转Object
	 * @param in
	 * @param clz
	 * @param ns 命名空间
	 * @param alisa 别名
	 * @return
	 * @throws Exception
	 */
	
	public static <T> T convert(InputStream in,Class<T> clz,String ns,String alisa) throws Exception {
		SAXReader saxReader = new SAXReader();
		Document doc = saxReader.read(in);
		Map<String,String> map = new HashMap<>();  
	    map.put(alisa,ns); 
	    saxReader.getDocumentFactory().setXPathNamespaceURIs(map);
		return convert(doc,clz);
	}
	
	
	
	/**
	 * document 转 Object
	 * @param doc
	 * @param clz
	 * @return
	 * @throws Exception 
	 */
	public static <T> T convert(Document doc,Class<T> clz) throws Exception {
		T t = clz.newInstance();
		getValue(doc, t, clz,"");
		return t;
	}
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private static void getValue(Document doc,Object obj,Class clz,String parentPath) throws Exception{
		
		Map<Field,XmlField> xmlType = XmlFieldBeanFactory.getForClass(clz);
		
		for(Field field : xmlType.keySet()) {
			XmlField xmlField = xmlType.get(field);
			Object value = field.getType().newInstance();
			BeanUtils.setProperty(obj, field.getName(), value);
			if(!xmlField.haveSon()) {
				if(isCollection(field.getType())) {
					Collection cl = (Collection) value;
					List<Node> nodes = doc.selectNodes(parentPath+xmlField.path());
					if(CollectionUtils.isNotEmpty(nodes)) {
						for (Node node : nodes) {
							cl.add(node.getText());
						}
					}
					
				}else {
					if(xmlField.isText()) {
						Node node = doc.selectSingleNode(parentPath+xmlField.path());
						if(node!=null) {
							BeanUtils.setProperty(obj,field.getName() , node.getText());
						}
					}else {
						BeanUtils.setProperty(obj,field.getName() , doc.valueOf(parentPath+xmlField.path()));
					}
				}
			}else {
				if(isCollection(field.getType())){
					Collection cl = (Collection) value;
					List<Node> nodes = doc.selectNodes(parentPath+xmlField.path());
					if(CollectionUtils.isNotEmpty(nodes)) {
						for (Node node : nodes) {
							 Type genericType = field.getGenericType();                   
							  if(genericType == null) 
								  return;                    // 如果是泛型参数的类型                    
							  if(genericType instanceof ParameterizedType){                        
								  ParameterizedType pt = (ParameterizedType) genericType;//得到泛型里的class类型对象                     
								  Class<?> accountPrincipalApproveClazz = (Class<?>)pt.getActualTypeArguments()[0];
								  Object v = accountPrincipalApproveClazz.newInstance();
								  cl.add(v);
								  getValue(node.getDocument(), v,accountPrincipalApproveClazz,node.getUniquePath());
							  }
						}
					}
				}else {
					  Node node = doc.selectSingleNode(xmlField.path());
					  if(node != null) {
						  Object v = field.getType().newInstance();
						  getValue(doc, v,field.getType(),node.getUniquePath());
					  }
					 
				}
			}
		}

	}
	
	
	 private static boolean isCollection(Class<?> type) {
		    return Collection.class.isAssignableFrom(type);
	 }
	

}

 

3、xmlField注解

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

/**
 * 用于注解字段对应的xpath,进行解析xml
 *
 */

@Retention(RUNTIME)
@Target(FIELD)
public @interface XmlField {
	/**
	 * xml对应的xPath路径
	 * @return
	 */
	String path();
	/**
	 * 是否嵌套对象
	 * @return
	 */
	boolean haveSon() default false;
	
	/**
	 * 取属性值
	 * @return
	 */
	boolean isText() default true;
}

4、Test

实体类

public class Grade {
	
	@XmlField(path = "/grade/student",haveSon=true)
	private ArrayList<Student> students;
	
	@XmlField(path = "/grade/gradeCode/text()",isText=false)
	private String gradeCode;
	
	@XmlField(path = "/grade/gradeName")
	private String gradeName;

    //省略get set方法
}


public class Student {
	
	@XmlField(path="/id")
	private String id;
	
	@XmlField(path="/name")
	private String name;
	
    //默认是直接获得text(),如果isText是false时,直接读取path的内容如@arr获取属性,text()获得文本内容
	@XmlField(path="/@aliso",isText=false)
	private String aliso;
   //省略get set方法
}

xml 文档内容

<grade>
    <gradeCode>SD</gradeCode>
    <gradeName>grade2</gradeName>
    <student aliso="aa">
      <id>1</id>
      <name>zhangsan</name>
    </student>
    <student aliso="bb">
      <id>2</id>
      <name>lisi</name>
    </student>
</grade>

测试 

public class Test {
	public static void main(String[] args) throws Exception {
		String xml = "<grade>\r\n" + 
				"    <gradeCode>SD</gradeCode>\r\n" + 
				"    <gradeName>grade2</gradeName>\r\n" + 
				"    <student aliso=\"aa\">\r\n" + 
				"      <id>1</id>\r\n" + 
				"      <name>zhangsan</name>\r\n" + 
				"    </student>\r\n" + 
				"    <student aliso=\"bb\">\r\n" + 
				"      <id>2</id>\r\n" + 
				"      <name>lisi</name>\r\n" + 
				"    </student>\r\n" + 
				"</grade>";
		Grade grade = XmlPathUtil.convert(xml, Grade.class);
		System.out.println(grade);
	}
}

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值