Java tutorial
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved. Portions Copyrighted 2012 Daniel * Huss. * * The contents of this file are subject to the terms of either the GNU General Public License * Version 2 only ("GPL") or the Common Development and Distribution License("CDDL") (collectively, * the "License"). You may not use this file except in compliance with the License. You can obtain a * copy of the License at http://www.netbeans.org/cddl-gplv2.html or nbbuild/licenses/CDDL-GPL-2-CP. * See the License for the specific language governing permissions and limitations under the * License. When distributing the software, include this License Header Notice in each file and * include the License file at nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this particular file * as subject to the "Classpath" exception as provided by Sun in the GPL Version 2 section of the * License file that accompanied this code. If applicable, add the following below the License * Header, with the fields enclosed by brackets [] replaced by your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * * Contributor(s): * * The Original Software is NetBeans. The Initial Developer of the Original Software is Sun * Microsystems, Inc. Portions Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. * * If you wish your version of this file to be governed by only the CDDL or only the GPL Version 2, * indicate your decision by adding "[Contributor] elects to include this software in this * distribution under the [CDDL or GPL Version 2] license." If you do not indicate a single choice * of license, a recipient has the option to distribute your version of this file under either the * CDDL, the GPL Version 2 or to extend the choice of license to its licensees as provided above. * However, if you add GPL Version 2 code and therefore, elected the GPL Version 2 license, then the * option applies only if the new code is made subject to such option by the copyright holder. */ package de.unentscheidbar.validation.internal; import java.beans.BeanInfo; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.reflect.Method; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentMap; import javax.annotation.Nonnull; import org.apache.commons.lang3.ClassUtils; import com.google.common.base.Equivalence; import com.google.common.base.Equivalence.Wrapper; import com.google.common.base.Throwables; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.MapMaker; public final class Beans { private Beans() { /* Do not instantiate */ } private static final Cache<Class<?>, ConcurrentMap<String, MethodHandle>> CACHE = CacheBuilder.newBuilder() .weakKeys().maximumSize(100).build(); public static <T> T propertyValue(Object bean, String propertyName) { try { ConcurrentMap<String, MethodHandle> methodHandles = CACHE.get(bean.getClass(), new Callable<ConcurrentMap<String, MethodHandle>>() { @Override public ConcurrentMap<String, MethodHandle> call() throws Exception { return new MapMaker().concurrencyLevel(2).makeMap(); } }); /* * We may assume this map only grows and never shrinks. It does not matter if the same * getter is added twice by concurrent invocations of this method. */ MethodHandle getter = methodHandles.get(propertyName); if (getter == null) { getter = getterMethod(bean.getClass(), propertyName); methodHandles.put(propertyName, getter); } assert getter != null; return (T) getter.invoke(bean); } catch (Throwable t) { throw Throwables.propagate(t); } } public static boolean hasReadableProperty(Class<?> beanClass, String propertyName, Class<?> returnType) { PropertyDescriptor pd = property(beanClass, propertyName); if (pd == null) return false; Method getter = pd.getReadMethod(); return (getter != null) && ClassUtils.isAssignable(getter.getReturnType(), returnType); } public static PropertyDescriptor property(Class<?> beanClass, String propertyName) { try { BeanInfo beanInfo = Introspector.getBeanInfo(beanClass); PropertyDescriptor[] propDescriptors = beanInfo.getPropertyDescriptors(); if (propDescriptors == null) { throw new IllegalArgumentException("Class " + beanClass.getName() + " does not provide property descriptors in its bean info."); } for (PropertyDescriptor pd : propDescriptors) { if (pd.getName().equals(propertyName)) { return pd; } } return null; } catch (IntrospectionException e) { throw Throwables.propagate(e.getCause()); } } public static @Nonnull MethodHandle getterMethod(Class<?> beanClass, String propertyName) { PropertyDescriptor pd = property(beanClass, propertyName); Method getter = pd == null ? null : pd.getReadMethod(); if (getter == null) { throw new IllegalArgumentException("Could not find a readable property named " + propertyName + " in class " + beanClass.getName()); } try { return MethodHandles.lookup().unreflect(getter); } catch (IllegalAccessException e) { throw new IllegalArgumentException("I do not have access to property read method " + getter); } } public static <O> Wrapper<O> identity(O o) { return Equivalence.identity().wrap(o); } }