再谈运行时动态修改注解

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

     在前篇文章中,提出了怎样动态修改注解的解决方案,需要说明的是更适用于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_

 

  

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值