`
niuzai
  • 浏览: 67926 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

再谈运行时动态修改注解

 
阅读更多

      前面贴出的《运行时动态修改注解》,好多同志私信于我表示不知道该怎么用?觉得有必要再谈一把~

     在前篇文章中,提出了怎样动态修改注解的解决方案,需要说明的是更适用于POJO动态映射的范围较小的情况。(POJO需要动态映射的表结构相同表名不同这个范围就比较小,或者增加修改某个属性。。。),如果整个对象需要动态映射不同结构的表,那就完全没必要了!倒是可以做到,却没什么意义。相当于一个POJO通吃~ 如果需要动态映射的范围太大,你就需要考虑是否是你方案的问题了-- 有必要用憨包儿呢特吗?!一般来说映射的东西是配置性的,初始化时就定了。我们动态映射已经违背常伦咯 搞太多的特殊化,还是不好的! 因此我就只动态映射表名,呵呵。。。

    下面咱们来说说咋个特殊化哈~ 注意咯

 

    1. 动态修改注解元凶:

       

/**
 * 对象池工具类
 * 
 * 目前提供ORM动态映射解决方案
 * 
 * @author andy.zheng
 * @since 2012.09.25 15:55 PM
 * @vesion 1.0
 * 
 */
public class ClassPoolUtils {
    
    
    /**
     * 运行时动态ORM表映射
     * 
     * 
     * @param entityClassName   待映射的实体全限定类名
     * @param tableName         待映射的表名
     * @return                  映射后的类对象
     */
    public static Class<?> tableMapping(String entityClassName, String tableName){
        Class<?> c = null;
        
        if(StringUtils.isEmpty(entityClassName) || StringUtils.isEmpty(tableName)){
            throw new IllegalArgumentException("The mapping parameter is invalid!");
        }
        
        try {
            ClassPool classPool = ClassPool.getDefault();
            classPool.appendClassPath(new ClassClassPath(ClassPoolUtils.class));
            classPool.importPackage("javax.persistence");
            CtClass clazz = classPool.get(entityClassName);
            clazz.defrost();
            ClassFile classFile = clazz.getClassFile();
           
            ConstPool constPool = classFile.getConstPool();
            Annotation tableAnnotation = new Annotation("javax.persistence.Table", constPool);
            tableAnnotation.addMemberValue("name", new StringMemberValue(tableName, constPool));
            // 获取运行时注解属性
            AnnotationsAttribute attribute = (AnnotationsAttribute)classFile.getAttribute(AnnotationsAttribute.visibleTag);
            attribute.addAnnotation(tableAnnotation);
            classFile.addAttribute(attribute);
            classFile.setVersionToJava5();
            //clazz.writeFile();
            
            //TODO 当前ClassLoader中必须尚未加载该实体。(同一个ClassLoader加载同一个类只会加载一次)
            //c = clazz.toClass();
            EntityClassLoader loader = new EntityClassLoader(ClassPoolUtils.class.getClassLoader());
            c = clazz.toClass(loader , null);
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return c;
    }  

    public static void main(String[] args) {
        Class<?> clazz = ClassPoolUtils.tableMapping("com.andy.model.order.Order", "order1");
        System.out.println("修改后的@Table: " + clazz.getAnnotation(Table.class));
    }
}

 

 2. PO类加载器:

/**
 * 实体类加载器
 * 
 * 该加载器主要用于运行时动态修改实体后,重新装载实体
 * 
 * @author andy.zheng
 * @since 2012.09.25 16:18 PM
 * @vesion 1.0
 *
 */
public class EntityClassLoader extends ClassLoader {
    
    private ClassLoader parent;
    
    public EntityClassLoader(ClassLoader parent){
        this.parent = parent;
    }
     
    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        return this.loadClass(name, false);
    }
    
    @Override
    protected synchronized Class<?> loadClass(String name, boolean resolve)
            throws ClassNotFoundException {
        Class<?> clazz = this.findLoadedClass(name);
        if(null != parent){
            clazz = parent.loadClass(name);
        }  
        if(null == clazz){
            this.findSystemClass(name);
        }
        
        if(null == clazz){
            throw new ClassNotFoundException();
        }
        if(null != clazz && resolve){
            this.resolveClass(clazz);
        }
        
        return clazz;
    }
    
    
    

    /**
     * @param args
     */
    public static void main(String[] args) {

    }

}

 

   3. 将最新映射对象交给Hibernate吧~ 当然这个东东当然在Dao层哈,需要覆盖hibernate初始化默认加载的映射对象。你可以把它正在诸如BaseHiberanteDao中,在需要动态映射表名的时候,先调它一把,然后再写你的HQL.当然如果接口统一的话,你也可以玩高级一点的。(为需要动态映射的接口代理一下,悄无声息的动态映射一把!!!可谓是神不知鬼不觉~),

  

    /**
     * 运行时动态ORM表映射
     * 
     * @param tableMapping  映射集合 
     *                      key - 待映射的表名 value - 待映射的实体对象
     */
    @SuppressWarnings("unused")
    protected void tableMapping(Map<String, Class<?>> tableMapping){
        Assert.notEmpty(tableMapping , "The mapping parameter is empty!");
        for (String tableName : tableMapping.keySet()) {
            Class<?> entityClass = tableMapping.get(tableName);
            String className = entityClass.getName();
            ClassMetadata metadata = this.getSessionFactory().getClassMetadata(className);
            Class<?> mappedClass = metadata.getMappedClass();
            mappedClass = ClassPoolUtils.tableMapping(className, tableName);
        }
    }

 

   调用例子:

  

public Page<OrderDetail> getList(int currentPage , int pageSize){
   this.tableMapping(new HashMap(){
      {
	            this.put("orderdetail1", OrderDetail.class);
       }
   });
  Page<OrderDetail> page = this.<OrderDetail>pagingList("", currentPage , pageSize);
  Assert.notEmpty(page.getItems());
  return page;
}

 

   执行语句:

  

  

Hibernate: select count(*) as col_0_0_ from OrderDetail orderdetai0_
Hibernate: select orderdetai0_.id as id15_, orderdetai0_.docid as docid15_, orderdetai0_.ErrorDesc as ErrorDesc15_, orderdetai0_.insertedtime as inserted3_15_, orderdetai0_.OrderID as OrderID15_, orderdetai0_.ordernum as ordernum15_, orderdetai0_.SegmentsIDs as Segments5_15_, orderdetai0_.selltype as selltype15_, orderdetai0_.status as status15_ from OrderDetail orderdetai0_

 

  

 

2
3
分享到:
评论
9 楼 mission 2016-01-29  
请问我获取到类后想要创建对象, 报错
java.lang.ClassCastException: com.cn.book.entity.TalkHishtory cannot be cast to com.cn.book.entity.TalkHishtory

同样的类型,却无法创建实例, 是不是线程安全方面的问题.
我邮箱: smallstring@163.com  帮忙解决下这个问题吧.
8 楼 zhs471420954 2013-05-18  
加入程序中执行没有效果啊,表名还是没有修改
7 楼 socialfist 2013-05-06  
呵呵,虽然放弃了这种很费力也没多大用处的方法,但还是很感谢博主的帮忙,了解了不少hibernate的知识。
最后还是用hibernate调用sql语句来解决的,写了一个公共的实体bean来用
6 楼 niuzai 2013-04-19  
socialfist 写道
老大我这怎么用不了啊,单独测试都是对的,就是查询的还是原来的表啊
是不是POJO那也要设置一下,@Table(name="tmp2013",catalog="str", schema="dbo")这个就这样写吗?老大传授传授经验吧,卡好几天了,用配置xml的也没成功,这个再不成功就真没辙 了

        Class<?> mappedClass = metadata.getMappedClass();  
        mappedClass = ClassPoolUtils.tableMapping(className, tableName); 

亲,以上代码不行哈~  问题不在于你我。由于原生Hibernate ORM映射管理器只暴露了读的接口,导致不能将动态映射后的实体设置进去。需要对Hibernate源码开刀哈~
具体参见:org.hibernate.persister.entity.AbstractEntityPersister getTableName()
注:Hiberante翻译HQL中的实体对象映射表名时调用该方法。
方案如下:
1.暴露AbstractEntityPersister中的setTableName接口;(动刀范围较小,层次太深已接近核心代码,可能花的时间较多);
2.扩展Hibernate Configuration类,将映射后的对象重新加载到Hibernate。(因为一个表名而已,需要动态加载整个对象,总感觉不爽~)
3.如果你的表名类似那种有规律可循的话,就不用考虑动态映射。(Hiberante提供了命名策略,它能处理首次加载已明确的表名(eg.加载当月的某张表),然而,针对与业务相关的情况还是力不从心的)
     
5 楼 socialfist 2013-04-15  
老大我这怎么用不了啊,单独测试都是对的,就是查询的还是原来的表啊
是不是POJO那也要设置一下,@Table(name="tmp2013",catalog="str", schema="dbo")这个就这样写吗?老大传授传授经验吧,卡好几天了,用配置xml的也没成功,这个再不成功就真没辙 了
4 楼 niuzai 2012-09-26  
投踩的兄弟请指点一二,不能只踩撒~
3 楼 niuzai 2012-09-26  
shenliuyang 写道
动态编译, 加载你都用上了。     如果觉得可以, 你就开放源代码给大家瞧瞧吧。

亲,没有其他代码了。上面是所有的代码哈
2 楼 shenliuyang 2012-09-26  
动态编译, 加载你都用上了。     如果觉得可以, 你就开放源代码给大家瞧瞧吧。
1 楼 niuzai 2012-09-26  
自己抢个沙发先~

相关推荐

    源码追踪经验谈

    源码追踪是软件开发中的重要技能,尤其是在调试和优化代码时。这份名为“源码追踪经验谈”的PDF文档,很可能是某位资深开发者或者技术专家根据自己的实践经历编写的,旨在分享他们在源码分析和调试过程中的技巧和...

    浅谈VB程序的调试和错误处理.

    2. **添加注释**:在代码中加入必要的注释,不仅可以帮助自己和其他开发者更好地理解代码意图,还能在后期修改或调试时提供参考。 3. **显式声明和引用对象**:使用`Dim`语句明确声明变量,避免拼写错误导致的新...

    浅谈jquery采用attr修改form表单enctype不起作用的问题

    在尝试使用jQuery的`attr`方法动态修改`enctype`属性时,例如: ```javascript $('form').attr('enctype', 'multipart/form-data'); ``` 在大多数现代浏览器中,这种方法是有效的。但不幸的是,旧版的Internet ...

    反射机制

    总之,Java反射机制是Java平台的强大功能,它允许程序在运行时动态地访问和修改类的行为。理解并熟练掌握反射机制,将有助于编写出更加灵活、强大的代码。不过,由于其潜在的安全性和性能问题,使用时应谨慎权衡。...

    PowerBuilder编程经验谈

    此外,PowerBuilder还支持脚本语言PBL,使得在运行时动态修改应用程序的行为成为可能。 在进行PowerBuilder开发时,应注重代码的结构和可维护性。使用类(Class)组织代码,可以实现代码复用和模块化,提高程序的可...

    浅谈设计获胜策略分析.pdf

    将它注释起来逐渐地优化,足够了即可保留所有的工作版本从编码到调试:空白是好的使用有意义的变量名不要重复使用变量逐步细化在写代码之前先写注释有可能的话尽量避免使用指针避免使用麻烦的动态存:静态地分配所有...

    ppk谈JavaScript.part03.rar

    《ppk谈JavaScript》系列是JavaScript领域的经典读物,作者ppk(Peter-Paul Koch)是一位知名的前端开发者和浏览器兼容性专家。在这个部分,我们聚焦于JavaScript的核心概念、语法以及在实际开发中的应用。 首先,...

    关于单片机STM32F103-F030的时钟浅谈

    在没有外部晶振时,应取消或注释掉这一定义,确保系统使用内部HSI。 总结来说,STM32F103和STM32F030的时钟管理涉及多个层面,包括选择合适的时钟源、配置PLL、切换时钟源以及调整系统配置。理解和熟练掌握这些知识...

    浅谈PHP的反射机制

    - 动态创建类或方法,实现运行时的类修改或扩展。 使用反射机制时,开发者需要特别注意,因为它可能会降低程序的性能,并且在一定程度上破坏封装性。因此,反射通常建议在没有其他替代方案的情况下使用,或者用在...

    试谈LabVIEW程序的内存优化.pdf

    * 我们可以放心地在 VI 的前面板(对于非界面 VI)和框图里添加图片、注释等信息来帮助编写、维护 LabVIEW 程序,这些帮助信息不会在 VI 运行时占用内存。 二、内存泄漏 LabVIEW 与 C 语言不同,它没有任何分配或...

    JavaScript 编写的带有源代码的快速笔记

    该项目为国外大神项目,可以作为毕业设计的项目,也可以作为大作业项目,不用担心代码重复,设计重复等,如果需要对项目进行修改,需要具备一定基础知识。 注意:如果装有360等杀毒软件,可能会出现误报的情况,源码...

    使用 JavaScript 编写的 Note App 源代码.zip

    该项目为国外大神项目,可以作为毕业设计的项目,也可以作为大作业项目,不用担心代码重复,设计重复等,如果需要对项目进行修改,需要具备一定基础知识。 注意:如果装有360等杀毒软件,可能会出现误报的情况,源码...

    使用 JavaScript 编写的 Notes 应用程序及其源代码.zip

    该项目为国外大神项目,可以作为毕业设计的项目,也可以作为大作业项目,不用担心代码重复,设计重复等,如果需要对项目进行修改,需要具备一定基础知识。 注意:如果装有360等杀毒软件,可能会出现误报的情况,源码...

    试谈自动化工具与框架实践.pptx

    在创建一个空的测试项目时,QTP提供了“Record and Run Setting”功能,允许用户设置录制和运行的参数。通过此设置,用户可以指定QTP在录制过程中应如何交互和访问目标应用程序。在开始录制前,确保已配置好这些设置...

    javaweb项目开发个人常见问题与经验浅谈.docx

    ### JavaWeb项目开发个人常见问题与经验浅谈 #### 一、业务逻辑 在JavaWeb项目的开发过程中,业务逻辑的设计尤为重要。它不仅关系到系统的稳定性,还直接影响用户体验和项目的后期维护成本。 - **对基础资料的...

    浅谈计算机软件工程维护措施.doc

    同时,编写清晰的文档和注释,以便于其他开发者理解和修改代码。此外,开发者还应遵循良好的编程规范,采用模块化设计,使得软件的维护和扩展变得更加容易。 2.2 实施系统化的维护流程 建立一套完善的软件维护流程...

    搭建WEB环境和初始了解jsp

    - 或者修改`conf/server.xml`配置文件,添加`&lt;Context&gt;`标签,指定应用程序路径。 二、使用 JSP 实现输出 1. **JSP 概述**: JSP是一种基于Java的服务器端脚本语言,用于生成动态HTML、XML或其他格式的文档。它...

    shell浅谈之十二shell调试及主题.docx

    - **清晰的注释**:为代码添加注释可以帮助理解脚本的目的和每个部分的作用,方便后期维护和调试。 - **模块化设计**:将复杂脚本分解为多个函数,便于测试和调试每个独立部分。 - **错误处理**:使用`if`语句...

    浅谈更新linux-3.2.5(关于linux-3.2.5内核的配置和编译).pdf

    《浅谈更新Linux-3.2.5:内核配置与编译详解》 Linux内核的更新和移植是一项技术性极强的工作,对于开发者来说,理解和掌握这一过程至关重要。本文将聚焦于Linux-3.2.5内核的配置和编译,以帮助读者深入理解如何将...

Global site tag (gtag.js) - Google Analytics