jaxb动态修改注解-类加载器

最近项目用到jaxb解析xml文件。需要定义一个javaBean模型。

@XmlAccessorType(XmlAccessType.FIELD)

@XmlType(name = "", propOrder = {"sender","sheet" })

@XmlRootElement(name = "AUTO ")

 

public class DataFile{

 

    @XmlElement(name="Sender",required = true)

    protected Sender sender;

   

    public Sender getSender() {

       return sender;

    }

    public void setSender(Sender sender) {

       this.sender = sender;

    }

 

现在遇到个问题,就是@XmlRootElement(name = "AUTO ")这个节点是动态的。但是注解在运行期间是改变不了得。那只有改字节码了。Asm?cglib? javassist?..等等修改字节码的库。比较方便的还是cglibjavassist吧。因为它们都是对Asm的封装。

/**

 * 运行时动态修改注解值

 * @author c_zhangzengmin002

 *

 */

public class ClassUtils {

 

    //缓存加载器加载的calss对象

    private static final Map<String, Class<?>> classPoolMap=new ConcurrentHashMap<String, Class<?>>();

   

    private ClassUtils(){}

   

    /**

     * 运行时动态修改注解值

     * @param Class

     *

     * @param entityClassName

     *            待映射的实体全限定类名

     * @param  annotation 需要修改的注解全限定类名

     * @param annotationAttrName 注解属性名称

     * @param annotationVal 注解属性值

     *           

     * @return 映射后的类对象

     */

    public static  Class<?> updateAnnotationForClass(String entityClassName,String annotationClassName, String annotationAttrName,String annotationVal)throws Exception {

       Class<?> c = null;

       if(StringUtil.isBlank(entityClassName) || StringUtil.isBlank(annotationClassName)

              || StringUtil.isBlank(annotationAttrName) || StringUtil.isBlank(annotationVal)){

           return c;

       }

       c=classPoolMap.get(annotationVal);

       if(null!=c){

           return c;

       }

       try {

           ClassPool classPool = ClassPool.getDefault();

           classPool.appendClassPath(new ClassClassPath(ClassUtils.class));

           //classPool.importPackage("javax.persistence");

           CtClass clazz = classPool.get(entityClassName);

           clazz.defrost();

           ClassFile classFile = clazz.getClassFile();

             

           ConstPool constPool = classFile.getConstPool();

           Annotation tableAnnotation = new Annotation(

                  annotationClassName, constPool);

           tableAnnotation.addMemberValue(annotationAttrName, new StringMemberValue(

                  annotationVal, constPool));

           // 获取运行时注解属性

           AnnotationsAttribute attribute = (AnnotationsAttribute) classFile

                  .getAttribute(AnnotationsAttribute.visibleTag);

           attribute.addAnnotation(tableAnnotation);

           classFile.addAttribute(attribute);

           classFile.setVersionToJava5();

           // clazz.writeFile();

            

           AnnotationClassLoader loader = new AnnotationClassLoader(

                  ClassUtils.class.getClassLoader());

//加载器加载class文件,一个加载器只会加载一次路径名称相同的calss

//这里因为只改了注解,类路径是没有改变的。

           c = clazz.toClass(loader, null);

           if(null!=c){

              classPoolMap.put(annotationVal, c);

           }

       } catch (Exception e) {

           e.printStackTrace();

       }

       return c;

    }

 

    public static void main(String[] args)throws Exception {       Class<?> clazz3 = ClassUtils.updateAnnotationForClass(

    "com.dep.jaxb.DataFile","javax.xml.bind.annotation.XmlRootElement","name", "AUTO_IDS");

       System.out.println("修改后的@XmlRootElement: " + clazz3.getAnnotation(XmlRootElement.class).name());

    }

}

 

/**

     * <p>

     * Description:根据class类型,将文件流转换成对象。在这个过程中会对文件进行编码处理

     * </p>

     * <p>

     * Create Time:2012-9-31

     * </p>

     *

     * @author zzm

     * @param Class

     *            <?>

     * @param BufferedReader

     *            文件流

     * @throws Exception

     */

    public static Object unmarshalClaim(Class<?> c, BufferedReader in)

           throws Exception {

       StringBuilder buffer = null;

       JAXBContext jaxbContext;

       try {

          

           buffer = new StringBuilder();

           String line = "";

           if (in != null) {

              while ((line = in.readLine()) != null) {

                  buffer.append(line);

              }

 

           }

          

           //所取头结点名称

           String dataFileName=StringUtil.getXMlHandleNodeString(buffer);

           //获取动态class对象

           Class<?> calss=ClassUtils.updateAnnotationForClass(Constant.DATAFILE_CLASS_NAME, Constant.XMLROOTELEMENT_CLASS_NAME,

                  Constant.NAME_STR, dataFileName);

           if(null!=calss){

              c=calss;

           }

           String xmlString = StringUtil.getXMlString(buffer);

          

           StreamSource streamSource = new StreamSource(new StringReader(

                  xmlString));

          

           // 加载映射bean

           jaxbContext = JAXBContext.newInstance(c);

           // 创建解析

           Unmarshaller um = jaxbContext.createUnmarshaller();

           return unmarshalClaim(um,streamSource);

       } catch (Exception e) {

           log.error(e);

           e.printStackTrace();

           throw new BasicException(e.getMessage());

       }finally{

           in.close();

       }

    }

 

问题来了!

public static void unmarshalClaim()throws Exception {

       String s = "E:\\Documents and Settings\\c_zhangzengmin002\\桌面\\xml\\1.xml";

       //xml动态的转换成相应的javaBean对象

       Object obj = JAXBUtil.unmarshalClaim(DataFile.class, s);

        //这样问题来了,这里强转报错了。因为要动态获取的class对象。这里是使用不同的加载器加载的calss对象实例。不同加载器加载的对象实例是不一样的。

       //DataFile newStudent = (DataFile) obj

    }

不同加载器加载同class对象实例是不一样的。当一个类实例化时,首先会对其父类实例化。

解决:

@XmlAccessorType(XmlAccessType.FIELD)

@XmlType(name = "", propOrder = {"sender","sheet" })

@XmlRootElement(name = "AUTO ")

public class DataFile extends AbstractDataFile{

 

    @XmlElement(name="Sender",required = true)

    protected Sender sender;

   

    public Sender getSender() {

       return sender;

    }

    public void setSender(Sender sender) {

       this.sender = sender;

    }

public abstract class AbstractDataFile {

 

    public Sender getSender() {return null;};

}

 

    public static void unmarshalClaim()throws Exception {

       String s = "E:\\Documents and Settings\\c_zhangzengmin002\\桌面\\xml\\1.xml";

        //自定义加载器加载的对象

       Object newStudent2 = JAXBUtil.unmarshalClaim(DataFile.class, s3);

       //默认加载器加载的对象

       DataFile dataFile =new DataFile();

       AbstractDataFile newStudent = (AbstractDataFile) newStudent2;

 

       System.out.println(dataFile.getClass().getClassLoader());

       System.out.println(newStudent.getClass().getClassLoader());

    //父类的加载器  System.out.println(dataFile.getClass().getSuperclass().getClassLoader());

    //父类的加载器  System.out.println(newStudent.getClass().getSuperclass().getClassLoader());

 

    }

运行结果:

sun.misc.Launcher$AppClassLoader@82ba41

com.dep.util.EntityClassLoader@a39137

sun.misc.Launcher$AppClassLoader@82ba41

sun.misc.Launcher$AppClassLoader@82ba41

结果发现,父类都是由同一加载器加载的。目前解决此问题就想到这个办。应该还有其他的方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值