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

com.caucho.util.BeanUtil Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 1998-2012 Caucho Technology -- all rights reserved
 *
 * This file is part of Resin(R) Open Source
 *
 * Each copy or derived work must preserve the copyright notice and this
 * notice unmodified.
 *
 * Resin Open Source is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Resin Open Source is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
 * of NON-INFRINGEMENT.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Resin Open Source; if not, write to the
 *   Free SoftwareFoundation, Inc.
 *   59 Temple Place, Suite 330
 *   Boston, MA 02111-1307  USA
 *
 * @author Scott Ferguson
 */

package com.caucho.util;

import com.caucho.vfs.Path;
import com.caucho.vfs.Vfs;

import java.beans.BeanInfo;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.logging.Logger;

/**
 * Bean utilities.
 */
public class BeanUtil {
  static final Logger log = Log.open(BeanUtil.class);
  static L10N L = new L10N(BeanUtil.class);

  /**
   * Returns the bean property type.
   *
   * @param obj the bean object
   * @param name the property name
   */
  public static Class
  getBeanPropertyClass(Object obj, String name)
  {
    Method method = getBeanPropertyMethod(obj, name);

    if (method == null)
      return null;

    Class []paramTypes = method.getParameterTypes();
    if (paramTypes.length == 1)
      return paramTypes[0];
    else
      return null;
  }

  /**
   * Returns the bean property type.
   *
   * @param obj the bean object
   * @param name the property name
   */
  public static Method
  getBeanPropertyMethod(Object obj, String name)
  {
    name = configToBeanName(name);

    Class beanClass = obj.getClass();
    Method method = getSetMethod(beanClass, name);

    if (method == null)
      method = getAddMethod(beanClass, name);

    return method;
  }

  public static void
  validateClass(Class cl, Class parent)
    throws RegistryException
  {
    if (parent.isAssignableFrom(cl)) {
    }
    else if (parent.isInterface())
      throw new RegistryException(L.l("{0} must implement {1}",
                                      cl.getName(), parent.getName()));
    else
      throw new RegistryException(L.l("{0} must extend {1}",
                                      cl.getName(), parent.getName()));

    if (cl.isInterface())
      throw new RegistryException(L.l("{0} must be a concrete class.",
                                      cl.getName()));
    
    if (Modifier.isAbstract(cl.getModifiers()))
      throw new RegistryException(L.l("{0} must not be abstract.",
                                      cl.getName()));
    
    if (! Modifier.isPublic(cl.getModifiers()))
      throw new RegistryException(L.l("{0} must be public.",
                                      cl.getName()));

    Constructor zero = null;
    try {
      zero = cl.getConstructor(new Class[0]);
    } catch (Throwable e) {
    }

    if (zero == null)
      throw new RegistryException(L.l("{0} must have a public zero-arg constructor.",
                                      cl.getName()));
  }

  /**
   * Returns the native path for a configured path name.  The special cases
   * $app-dir and $resin-home specify the root directory.
   *
   * @param pathName the configuration path name.
   * @param varMap the map of path variables.
   * @param pwd the default path.
   *
   * @return a real path corresponding to the path name
   */
  public static Path lookupPath(String pathName, HashMap varMap, Path pwd)
  {
    if (pwd == null)
      pwd = Vfs.lookup();
    
    if (pathName.startsWith("$")) {
      int p = pathName.indexOf('/');
      String prefix;
      String suffix;
      
      if (p > 0) {
        prefix = pathName.substring(1, p);
        suffix = pathName.substring(p + 1);
      }
      else {
        prefix = pathName.substring(1);
        suffix = null;
      }

      Object value = varMap != null ? varMap.get(prefix) : null;
      if (value instanceof Path) {
        pwd = (Path) value;
        pathName = suffix;
      }
    }

    if (pathName == null)
      return pwd;
    else if (pathName.indexOf('$') < 0)
      return pwd.lookup(pathName);
    
    CharBuffer cb = CharBuffer.allocate();
    int head = 0;
    int tail = 0;
    while ((tail = pathName.indexOf('$', head)) >= 0) {
      cb.append(pathName.substring(head, tail));

      if (tail + 1 == pathName.length()) {
        cb.append('$');
        continue;
      }

      int ch = pathName.charAt(tail + 1);
      
      if (ch >= '0' && ch <= '9') {
        for (head = tail + 1; head < pathName.length(); head++) {
          ch = pathName.charAt(head);
        
          if (ch < '0' || ch > '9')
            break;
        }
      }
      else {
        for (head = tail + 1; head < pathName.length(); head++) {
          ch = pathName.charAt(head);
        
          if (ch == '/' || ch == '\\' || ch == '$' || ch == ' ')
            break;
        }
      }

      String key = pathName.substring(tail + 1, head);
      Object value = varMap != null ? varMap.get(key) : null;

      if (value == null)
        value = System.getProperty(key);

      if (value != null)
        cb.append(value);
      else
        cb.append(pathName.substring(tail, head));
    }

    if (head > 0 && head < pathName.length())
      cb.append(pathName.substring(head));
    
    return pwd.lookupNative(cb.close());
  }

  /**
   * Translates a configuration name to a bean name.
   *
   * 
   * foo-bar maps to fooBar
   * 
*/ private static String configToBeanName(String name) { CharBuffer cb = CharBuffer.allocate(); for (int i = 0; i < name.length(); i++) { char ch = name.charAt(i); if (ch == '-') cb.append(Character.toUpperCase(name.charAt(++i))); else cb.append(ch); } return cb.close(); } /** * Returns an add method matching the name. */ private static Method getAddMethod(Class cl, String name) { name = "add" + name; Method []methods = cl.getMethods(); for (int i = 0; i < methods.length; i++) { if (! Modifier.isPublic(methods[i].getModifiers())) continue; if (! name.equalsIgnoreCase(methods[i].getName())) continue; if (methods[i].getParameterTypes().length == 1) return methods[i]; } return null; } /** * Returns the method matching the name. */ static private Method getMethod(Method []methods, String name) { Method method = null; for (int i = 0; i < methods.length; i++) { method = methods[i]; if (! Modifier.isPublic(method.getModifiers())) continue; if (! Modifier.isPublic(method.getDeclaringClass().getModifiers())) continue; if (method.getName().equals(name)) return method; } return null; } /** * Returns the method matching the name. */ static private Method getMethod(Method []methods, String name, Class []params) { Method method = null; loop: for (int i = 0; i < methods.length; i++) { method = methods[i]; if (! Modifier.isPublic(method.getModifiers())) continue; if (! Modifier.isPublic(method.getDeclaringClass().getModifiers())) continue; if (! method.getName().equals(name)) continue; Class []actual = method.getParameterTypes(); if (actual.length != params.length) continue; for (int j = 0; j < actual.length; j++) { if (! actual[j].isAssignableFrom(params[j])) continue loop; } return method; } return null; } /** * Returns a set method matching the property name. */ public static Method getSetMethod(BeanInfo info, String propertyName) { // jsp/184c, jsp/184z, jsp/18o1 bug #2634, #3066 Method method = getSetMethod(info.getBeanDescriptor().getBeanClass(), propertyName); PropertyDescriptor []pds = info.getPropertyDescriptors(); Method bestMethod = method; for (int i = 0; i < pds.length; i++) { if (pds[i].getName().equals(propertyName) && pds[i].getWriteMethod() != null) { Method writeMethod = pds[i].getWriteMethod(); if (method != null && writeMethod.getName().equals(method.getName())) continue; if (writeMethod.getParameterTypes()[0].equals(String.class)) return writeMethod; else bestMethod = writeMethod; } } return bestMethod; } /** * Returns a set method matching the property name. */ public static Method getSetMethod(Class cl, String propertyName) { Method method = getSetMethod(cl, propertyName, false); if (method != null) return method; return getSetMethod(cl, propertyName, true); } /** * Returns a set method matching the property name. */ public static Method getSetMethod(Class cl, String propertyName, boolean ignoreCase) { String setName = "set" + propertyNameToMethodName(propertyName); Method bestMethod = null; for (Class ptrCl = cl; ptrCl != null; ptrCl = ptrCl.getSuperclass()) { Method method = getSetMethod(ptrCl.getMethods(), setName, ignoreCase); if (method != null && method.getParameterTypes()[0].equals(String.class)) return method; else if (method != null) bestMethod = method; } if (bestMethod != null) return bestMethod; Class []interfaces = cl.getInterfaces(); for (int i = 0; i < interfaces.length; i++) { Method method = getSetMethod(interfaces[i].getMethods(), setName, ignoreCase); if (method != null && method.getParameterTypes()[0].equals(String.class)) return method; else if (method != null) bestMethod = method; } if (bestMethod != null) return bestMethod; return null; } /** * Finds the matching set method * * @param method the methods for the class * @param setName the method name */ private static Method getSetMethod(Method []methods, String setName, boolean ignoreCase) { Method bestMethod = null; for (int i = 0; i < methods.length; i++) { Method method = methods[i]; // The method name must match if (! ignoreCase && ! method.getName().equals(setName)) continue; // The method name must match if (ignoreCase && ! method.getName().equalsIgnoreCase(setName)) continue; // The method must be public if (! Modifier.isPublic(method.getModifiers())) continue; // It must be in a public class or interface if (! Modifier.isPublic(method.getDeclaringClass().getModifiers())) continue; // It must have a single parameter if (method.getParameterTypes().length != 1) continue; // It must return void if (! method.getReturnType().equals(void.class)) continue; Class paramType = method.getParameterTypes()[0]; if (paramType.equals(String.class)) return method; else if (bestMethod == null) bestMethod = method; else if (paramType.getName().compareTo(bestMethod.getParameterTypes()[0].getName()) < 0) bestMethod = method; } return bestMethod; } /** * Returns a set method matching the property name. */ public static Method getGetMethod(BeanInfo info, String propertyName) { PropertyDescriptor []pds = info.getPropertyDescriptors(); for (int i = 0; i < pds.length; i++) { if (pds[i].getName().equals(propertyName) && pds[i].getReadMethod() != null) { if (! Modifier.isPublic(pds[i].getReadMethod().getDeclaringClass().getModifiers())) { try { pds[i].getReadMethod().setAccessible(true); } catch (Throwable e) { continue; } } return pds[i].getReadMethod(); } } return getGetMethod(info.getBeanDescriptor().getBeanClass(), propertyName); } /** * Returns a get method matching the property name. */ public static Method getGetMethod(Class cl, String propertyName) { Method method = getGetMethod(cl, propertyName, false); if (method != null) return method; return getGetMethod(cl, propertyName, true); } /** * Returns a get method matching the property name. */ public static Method getGetMethod(Class cl, String propertyName, boolean ignoreCase) { String getName = "get" + propertyNameToMethodName(propertyName); String isName = "is" + propertyNameToMethodName(propertyName); for (Class ptrCl = cl; ptrCl != null; ptrCl = ptrCl.getSuperclass()) { Method method = getGetMethod(ptrCl.getDeclaredMethods(), getName, isName, ignoreCase); if (method != null) return method; Class []interfaces = ptrCl.getInterfaces(); for (int i = 0; i < interfaces.length; i++) { method = getGetMethod(interfaces[i].getDeclaredMethods(), getName, isName, ignoreCase); if (method != null) return method; } } return null; } /** * Finds the matching set method * * @param method the methods for the class * @param setName the method name */ private static Method getGetMethod(Method []methods, String getName, String isName, boolean ignoreCase) { for (int i = 0; i < methods.length; i++) { Method method = methods[i]; // The method must be public if (! Modifier.isPublic(method.getModifiers())) continue; // It must be in a public class or interface if (! Modifier.isPublic(method.getDeclaringClass().getModifiers())) continue; // It must have no parameters if (method.getParameterTypes().length != 0) continue; // It must not return void if (method.getReturnType().equals(void.class)) continue; // If it matches the get name, it's the right method else if (! ignoreCase && methods[i].getName().equals(getName)) return methods[i]; // If it matches the get name, it's the right method else if (ignoreCase && methods[i].getName().equalsIgnoreCase(getName)) return methods[i]; // The is methods must return boolean else if (! methods[i].getReturnType().equals(boolean.class)) continue; // If it matches the is name, it must return boolean else if (! ignoreCase && methods[i].getName().equals(isName)) return methods[i]; // If it matches the is name, it must return boolean else if (ignoreCase && methods[i].getName().equalsIgnoreCase(isName)) return methods[i]; } return null; } /** * Converts a user's property name to a bean method name. * * @param propertyName the user property name * @return the equivalent bean method name */ public static String propertyNameToMethodName(String propertyName) { char ch = propertyName.charAt(0); if (Character.isLowerCase(ch)) propertyName = Character.toUpperCase(ch) + propertyName.substring(1); return propertyName; } /** * Converts a user's property name to a bean method name. * * @param methodName the method name * @return the equivalent property name */ public static String methodNameToPropertyName(BeanInfo info, String methodName) { PropertyDescriptor []pds = info.getPropertyDescriptors(); for (int i = 0; i < pds.length; i++) { if (pds[i].getReadMethod() != null && pds[i].getReadMethod().getName().equals(methodName)) return pds[i].getName(); if (pds[i].getWriteMethod() != null && pds[i].getWriteMethod().getName().equals(methodName)) return pds[i].getName(); } return methodNameToPropertyName(methodName); } /** * Converts a user's property name to a bean method name. * * @param methodName the method name * @return the equivalent property name */ public static String methodNameToPropertyName(String methodName) { if (methodName.startsWith("get")) methodName = methodName.substring(3); else if (methodName.startsWith("set")) methodName = methodName.substring(3); else if (methodName.startsWith("is")) methodName = methodName.substring(2); if (methodName.length() == 0) return null; char ch = methodName.charAt(0); if (Character.isUpperCase(ch) && (methodName.length() == 1 || ! Character.isUpperCase(methodName.charAt(1)))) { methodName = Character.toLowerCase(ch) + methodName.substring(1); } return methodName; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy