All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.oschina.bilbodai.common.beanutil.property.PropertyUtil Maven / Gradle / Ivy

There is a newer version: 3.1.4
Show newest version
/*
* Copyright (c) 2014 Qunar.com. All Rights Reserved.
*/
package net.oschina.bilbodai.common.beanutil.property;

import net.oschina.bilbodai.common.beanutil.core.ASMCodeGenerator;
import net.oschina.bilbodai.common.beanutil.property.asm.lexer.code.CodeAppliers;
import net.oschina.bilbodai.common.beanutil.property.asm.lexer.parse.ITokenIterator;
import net.oschina.bilbodai.common.beanutil.property.asm.lexer.parse.StringTokenizerIterator;
import net.oschina.bilbodai.common.beanutil.property.asm.lexer.parse.Token;
import net.oschina.bilbodai.common.beanutil.runtime.IRuntimeClassLoader;
import net.oschina.bilbodai.common.beanutil.runtime.RuntimeClassLoader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import java.io.Closeable;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.FutureTask;

import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
import static org.objectweb.asm.Opcodes.ALOAD;
import static org.objectweb.asm.Opcodes.ARETURN;

/**
 * 每个独立的属性路径都会生成一个class,比如 x.y.z 和 x.y.k
 * 同时对于list和array,每个获取的位置也会产生一个,比如 x.y[0] 和 x.y[1]
 * 对map来说,每个key也会, 比如 x.key1 和 x.key2
 * 所以这是一个很明显的缺点,会增加class的内存开销
 * 但这个问题可以通过缓存和失效来控制
 * 如果需要控制加载累的数量{@link #cacheProperties}
 * 
 * {@link StringTokenizerIterator} {@code ->} {@link Token} {@code ->} {@link CodeAppliers}
 * 
* * @author qt-maodai Date: 15-8-8 Time: 下午1:12 * @version $Id$ */ public class PropertyUtil implements Closeable { private static IRuntimeClassLoader classLoader; private static PrintWriter printWriter; static { classLoader = AccessController.doPrivileged(new PrivilegedAction() { public IRuntimeClassLoader run() { return new RuntimeClassLoader(PropertyUtil.class.getClassLoader()); } }); } private final static ConcurrentHashMap> cacheProperties = new ConcurrentHashMap>(); /** * 根据实例所在的属性路径字符串获取实例中属性值 * * @param propertyPath 属性路径,类似 user.books[0].name * @param bean 实例,如 user * @return user第一本书的名字,注意如果中途某个属性为null,将抛出空指针异常,另外可能会抛出数组越界异常 */ public static Object getProperty(final String propertyPath, final Object bean) { if (propertyPath == null || propertyPath.trim().length() == 0) { throw new IllegalArgumentException("propertyPath can't be null"); } final String cacheKey = bean.getClass().getName() + "." + propertyPath; FutureTask task = cacheProperties.get(cacheKey); if (task != null) { return getCachedProperty(cacheKey, task).get(bean); } task = new FutureTask<>(new Callable() { public Property call() throws Exception { return make(propertyPath, bean.getClass()); } }); FutureTask existedTask = cacheProperties.putIfAbsent(cacheKey, task); if (existedTask == null) { existedTask = task; existedTask.run(); } return getCachedProperty(cacheKey, existedTask).get(bean); } public static Property make(String propertyPath, final Class beanType) throws Exception { StringTokenizerIterator stringTokenizerIterator = new StringTokenizerIterator(propertyPath); ASMCodeGenerator asmCodeGenerator = new ASMCodeGenerator(Opcodes.V1_6, classLoader, printWriter, Object.class, Property.class) { @Override public void onVisitorMethods(ClassVisitor cw, Object... args) throws Exception { ITokenIterator iterator = (ITokenIterator) args[0]; Class rootBeanType = (Class) args[1]; MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "get", "(Ljava/lang/Object;)Ljava/lang/Object;", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 1); new Token().apply(mv, iterator, rootBeanType); mv.visitInsn(ARETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } }; Class generateClass = asmCodeGenerator.getLoadedClass(stringTokenizerIterator, beanType); return (Property) generateClass.newInstance(); } private static Property getCachedProperty(final String cacheKey, FutureTask task) { try { return task.get(); } catch (Exception e) { cacheProperties.remove(cacheKey); throw new IllegalStateException("获取路径为" + cacheKey + "的属性值出错", e); } } /** * 如果要打印class生成的日志,可以设置相应的输出流 * @param out 输出流 */ public static void setTrace(OutputStream out) { printWriter = new PrintWriter(new OutputStreamWriter(out)); } public void close() throws IOException { if (printWriter != null) { printWriter.close(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy