/* * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net). *
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; * you may not use this file except in compliance with the License. * You may obtain a copy of the License at *
* http://www.gnu.org/licenses/lgpl.html *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.dreamlu.mica.core.beans;
import org.springframework.asm.ClassVisitor;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.cglib.core.AbstractClassGenerator;
import org.springframework.cglib.core.ReflectUtils;
import java.security.ProtectionDomain;
/**
* 重写 cglib BeanMap,支持链式bean
*
* @author L.cm
*/
public abstract class MicaBeanMap extends BeanMap {
private static final String BEAN_NAME_PREFIX = MicaBeanMap.class.getName();
protected MicaBeanMap() {}
protected MicaBeanMap(Object bean) {
super(bean);
}
public static MicaBeanMap create(Object bean) {
MicaGenerator gen = new MicaGenerator();
gen.setBean(bean);
gen.setContextClass(MicaBeanMap.class);
gen.setNamePrefix(BEAN_NAME_PREFIX);
gen.setUseCache(true);
return gen.create();
}
/**
* newInstance
*
* @param o Object
* @return MicaBeanMap
*/
@Override
public abstract MicaBeanMap newInstance(Object o);
public static class MicaGenerator extends AbstractClassGenerator {
private static final Source SOURCE = new Source(MicaBeanMap.class.getName());
private Object bean;
private Class beanClass;
private int require;
public MicaGenerator() {
super(SOURCE);
}
/**
* Set the bean that the generated map should reflect. The bean may be swapped
* out for another bean of the same type using {@link #setBean}.
* Calling this method overrides any value previously set using {@link #setBeanClass}.
* You must call either this method or {@link #setBeanClass} before {@link #create}.
* @param bean the initial bean
*/
public void setBean(Object bean) {
this.bean = bean;
if (bean != null) {
beanClass = bean.getClass();
}
}
/**
* Set the class of the bean that the generated map should support.
* You must call either this method or {@link #setBeanClass} before {@link #create}.
* @param beanClass the class of the bean
*/
public void setBeanClass(Class beanClass) {
this.beanClass = beanClass;
}
/**
* Limit the properties reflected by the generated map.
* @param require any combination of {@link #REQUIRE_GETTER} and
* {@link #REQUIRE_SETTER}; default is zero (any property allowed)
*/
public void setRequire(int require) {
this.require = require;
}
@Override
protected ClassLoader getDefaultClassLoader() {
return beanClass.getClassLoader();
}
@Override
protected ProtectionDomain getProtectionDomain() {
return ReflectUtils.getProtectionDomain(beanClass);
}
/**
* Create a new instance of the BeanMap
. An existing
* generated class will be reused if possible.
* @return {MicaBeanMap}
*/
public MicaBeanMap create() {
if (beanClass == null) {
throw new IllegalArgumentException("Class of bean unknown");
}
MicaBeanMapKey key = new MicaBeanMapKey(beanClass, require);
return (MicaBeanMap)super.create(key);
}
@Override
public void setNamePrefix(String namePrefix) {
super.setNamePrefix(namePrefix);
}
@Override
public void generateClass(ClassVisitor v) throws Exception {
new MicaBeanMapEmitter(v, getClassName(), beanClass, require);
}
@Override
protected Object firstInstance(Class type) {
return ((BeanMap)ReflectUtils.newInstance(type)).newInstance(bean);
}
@Override
protected Object nextInstance(Object instance) {
return ((BeanMap)instance).newInstance(bean);
}
}
}