View Javadoc
1   package org.codehaus.plexus.interpolation.reflection;
2   
3   /*
4    * Copyright 2001-2006 Codehaus Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  import org.codehaus.plexus.interpolation.util.StringUtils;
20  
21  import java.lang.ref.SoftReference;
22  import java.lang.ref.WeakReference;
23  import java.lang.reflect.Method;
24  import java.util.Map;
25  import java.util.StringTokenizer;
26  import java.util.WeakHashMap;
27  
28  /**
29   * <b>NOTE:</b> This class was copied from plexus-utils, to allow this library
30   * to stand completely self-contained.
31   * <br/>
32   * Using simple dotted expressions extract the values from a MavenProject
33   * instance, For example we might want to extract a value like:
34   * project.build.sourceDirectory
35   *
36   * @author <a href="mailto:jason@maven.org">Jason van Zyl </a>
37   * @version $Id$
38   */
39  public class ReflectionValueExtractor
40  {
41      private static final Class<?>[] CLASS_ARGS = new Class[0];
42  
43      private static final Object[] OBJECT_ARGS = new Object[0];
44  
45      /**
46       * Use a WeakHashMap here, so the keys (Class objects) can be garbage collected.
47       * This approach prevents permgen space overflows due to retention of discarded
48       * classloaders.
49       */
50      private static final Map<Class<?>, WeakReference<ClassMap>> classMaps = new WeakHashMap<Class<?>, WeakReference<ClassMap>>();
51  
52      private ReflectionValueExtractor()
53      {
54      }
55  
56      public static Object evaluate( String expression, Object root )
57          throws Exception
58      {
59          return evaluate( expression, root, true );
60      }
61  
62      // TODO: don't throw Exception
63      public static Object evaluate( String expression, Object root, boolean trimRootToken )
64          throws Exception
65      {
66          // if the root token refers to the supplied root object parameter, remove it.
67          if ( trimRootToken )
68          {
69              expression = expression.substring( expression.indexOf( '.' ) + 1 );
70          }
71  
72          Object value = root;
73  
74          // ----------------------------------------------------------------------
75          // Walk the dots and retrieve the ultimate value desired from the
76          // MavenProject instance.
77          // ----------------------------------------------------------------------
78  
79          StringTokenizer parser = new StringTokenizer( expression, "." );
80  
81          while ( parser.hasMoreTokens() )
82          {
83              String token = parser.nextToken();
84  
85              if ( value == null )
86              {
87                  return null;
88              }
89  
90              ClassMap classMap = getClassMap( value.getClass() );
91  
92              String methodBase = StringUtils.capitalizeFirstLetter( token );
93  
94              String methodName = "get" + methodBase;
95  
96              Method method = classMap.findMethod( methodName, CLASS_ARGS );
97  
98              if ( method == null )
99              {
100                 // perhaps this is a boolean property??
101                 methodName = "is" + methodBase;
102 
103                 method = classMap.findMethod( methodName, CLASS_ARGS );
104             }
105 
106             if ( method == null )
107             {
108                 return null;
109             }
110 
111             value = method.invoke( value, OBJECT_ARGS );
112         }
113 
114         return value;
115     }
116 
117     private static ClassMap getClassMap( Class<?> clazz )
118     {
119         WeakReference<ClassMap> ref = classMaps.get( clazz);
120 
121         ClassMap classMap;
122 
123         if ( ref == null || (classMap = ref.get()) == null )
124         {
125             classMap = new ClassMap( clazz );
126 
127             classMaps.put( clazz, new WeakReference<ClassMap>(classMap) );
128         }
129 
130         return classMap;
131     }
132 }