/*
* Copyright 2014 mango.jfaster.org
*
* The Mango Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 org.jfaster.mango.invoker;
import org.jfaster.mango.exception.UncheckedException;
import org.jfaster.mango.util.local.CacheLoader;
import org.jfaster.mango.util.local.DoubleCheckCache;
import org.jfaster.mango.util.local.LoadingCache;
import javax.annotation.Nullable;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.*;
/**
* @author ash
*/
public class InvokerCache {
@Nullable
public static GetterInvoker getNullableGetterInvoker(Class<?> clazz, String propertyName) {
return cache.get(clazz).getGetterInvoker(propertyName);
}
public static GetterInvoker getGetterInvoker(Class<?> clazz, String propertyName) {
GetterInvoker invoker = getNullableGetterInvoker(clazz, propertyName);
if (invoker == null) {
throw new UnreachablePropertyException("There is no getter for property named '" + propertyName + "' in '" + clazz + "'");
}
return invoker;
}
public static List<GetterInvoker> getGetterInvokers(Class<?> clazz) {
return cache.get(clazz).getGetterInvokers();
}
@Nullable
public static SetterInvoker getNullableSetterInvoker(Class<?> clazz, String propertyName) {
return cache.get(clazz).getSetterInvoker(propertyName);
}
public static SetterInvoker getSetterInvoker(Class<?> clazz, String propertyName) {
SetterInvoker invoker = cache.get(clazz).getSetterInvoker(propertyName);
if (invoker == null) {
throw new UnreachablePropertyException("There is no setter for property named '" + propertyName + "' in '" + clazz + "'");
}
return invoker;
}
public static List<SetterInvoker> getSetterInvokers(Class<?> clazz) {
return cache.get(clazz).getSetterInvokers();
}
private final static LoadingCache<Class<?>, BeanInfo> cache = new DoubleCheckCache<Class<?>, BeanInfo>(
new CacheLoader<Class<?>, BeanInfo>() {
public BeanInfo load(Class<?> clazz) {
try {
return new BeanInfo(clazz);
} catch (Exception e) {
throw new UncheckedException(e.getMessage(), e);
}
}
});
private static class BeanInfo {
private final Map<String, GetterInvoker> getterInvokerMap;
private final Map<String, SetterInvoker> setterInvokerMap;
private final List<GetterInvoker> getterInvokers;
private final List<SetterInvoker> setterInvokers;
public BeanInfo(Class<?> clazz) throws Exception {
Map<String, GetterInvoker> gim = new HashMap<String, GetterInvoker>();
Map<String, SetterInvoker> sim = new HashMap<String, SetterInvoker>();
List<GetterInvoker> gis = new ArrayList<GetterInvoker>();
List<SetterInvoker> sis = new ArrayList<SetterInvoker>();
java.beans.BeanInfo beanInfo = Introspector.getBeanInfo(clazz);
for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
if (!Class.class.equals(pd.getPropertyType())) {
String name = pd.getName();
String bname = isBoolean(pd.getPropertyType()) ?
"is" + Character.toUpperCase(name.charAt(0)) + name.substring(1, name.length()) :
null;
Method readMethod = pd.getReadMethod();
if (readMethod != null) {
FunctionalGetterInvoker fgi = FunctionalGetterInvoker.create(name, readMethod);
gim.put(name, fgi);
gis.add(fgi);
if (bname != null) { // 特殊处理boolean类型
FunctionalGetterInvoker bfgi = FunctionalGetterInvoker.create(bname, readMethod);
gim.put(bname, bfgi);
gis.add(bfgi);
}
}
Method writeMethod = pd.getWriteMethod();
if (writeMethod != null) { // 特殊处理boolean类型
FunctionalSetterInvoker fsi = FunctionalSetterInvoker.create(name, writeMethod);
sim.put(name, fsi);
sis.add(fsi);
if (bname != null) {
FunctionalSetterInvoker bfsi = FunctionalSetterInvoker.create(bname, writeMethod);
sim.put(bname, bfsi);
sis.add(bfsi);
}
}
}
}
getterInvokerMap = Collections.unmodifiableMap(gim);
setterInvokerMap = Collections.unmodifiableMap(sim);
getterInvokers = Collections.unmodifiableList(gis);
setterInvokers = Collections.unmodifiableList(sis);
}
GetterInvoker getGetterInvoker(String propertyName) {
return getterInvokerMap.get(propertyName);
}
SetterInvoker getSetterInvoker(String propertyName) {
return setterInvokerMap.get(propertyName);
}
private List<GetterInvoker> getGetterInvokers() {
return getterInvokers;
}
private List<SetterInvoker> getSetterInvokers() {
return setterInvokers;
}
private static boolean isBoolean(Class<?> clazz) {
return boolean.class.equals(clazz) || Boolean.class.equals(clazz);
}
}
}