View Javadoc

1   /*
2    * Copyright 2005 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at 
7    * 
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software 
11   * distributed under the License is distributed on an "AS IS" BASIS, 
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
13   * See the License for the specific language governing permissions and 
14   * limitations under the License.
15   */
16  
17  package org.apache.jdo.impl.model.java;
18  
19  import java.security.AccessController;
20  import java.security.PrivilegedAction;
21  import java.lang.reflect.Field;
22  
23  import org.apache.jdo.model.ModelFatalException;
24  import org.apache.jdo.model.java.JavaField;
25  import org.apache.jdo.model.java.JavaType;
26  import org.apache.jdo.model.jdo.JDOField;
27  import org.apache.jdo.util.I18NHelper;
28  
29  /***
30   * This class provides a basic JavaField implementation using a reflection
31   * Field instance. The implementation supports lazy initialization of the
32   * wrapped reflection field instance (see 
33   * {@link #BaseReflectionJavaField(String fieldName, JavaType declaringClass)}.
34   * <p>
35   * Note, this implementation is not connected to a JavaModelFactory, thus
36   * it can only support predefined types as field types.
37   * @see PredefinedType
38   * @author Michael Bouschen
39   * @since JDO 1.1
40   * @version JDO 2.0
41   */
42  public class BaseReflectionJavaField
43      extends AbstractJavaMember
44      implements JavaField
45  {
46      /*** The wrapped java.lang.reflect.Field instance. */
47      private Field field;
48  
49      /*** The type of the field. */
50      protected JavaType type;
51  
52      /*** I18N support */
53      private final static I18NHelper msg = 
54          I18NHelper.getInstance(BaseReflectionJavaField.class);
55  
56      /*** 
57       * Constructor taking a reflection field representation. The specifie
58       * field must not be <code>null</code>. 
59       * @param field the java.lang.reflect.Field instance
60       * @param declaringClass the JavaType of the declaring class or interface.
61       */
62      protected BaseReflectionJavaField(Field field, JavaType declaringClass)
63      {
64          super((field == null) ? null : field.getName(), declaringClass);
65          if (field == null)
66              throw new ModelFatalException(msg.msg(
67                  "ERR_InvalidNullFieldInstance", "BaseReflectionJavaField.<init>")); //NOI18N
68          this.field = field;
69      }
70      
71      /*** 
72       * Constructor taking the field name. This constructor allows lazy
73       * initialization of the field reference. 
74       * @param fieldName the name of the field.
75       * @param declaringClass the JavaType of the declaring class or interface.
76       */
77      protected BaseReflectionJavaField(String fieldName, JavaType declaringClass)
78      {
79          super(fieldName, declaringClass);
80      }
81  
82      // ===== Methods specified in JavaElement =====
83  
84      /***
85       * Returns the environment specific instance wrapped by this JavaModel
86       * element. This implementation returns the
87       * <code>java.lang.reflect.Field</code> instance for this JavaField.
88       * @return the environment specific instance wrapped by this JavaModel
89       * element.
90       */
91      public Object getUnderlyingObject() 
92      {
93          return getField();
94      }
95  
96      // ===== Methods specified in JavaMember =====
97  
98      /***
99       * Returns the Java language modifiers for the field represented by
100      * this JavaField, as an integer. The java.lang.reflect.Modifier class
101      * should be used to decode the modifiers. 
102      * @return the Java language modifiers for this JavaField
103      * @see java.lang.reflect.Modifier
104      */
105     public int getModifiers()
106     {
107         ensureInitializedField();
108         return field.getModifiers();
109     }
110 
111     // ===== Methods specified in JavaField =====
112 
113     /***
114      * Returns the JavaType representation of the field type.
115      * @return field type
116      */
117     public JavaType getType()
118     {
119         if (type == null) {
120             ensureInitializedField();
121             String typeName = field.getType().getName();
122             // Note, this only checks for predefined types!
123             type = PredefinedType.getPredefinedType(typeName);
124         }
125         return type;
126     }
127     
128     // ===== Methods not specified in JavaField =====
129 
130     /*** 
131      * Returns the java.lang.reflect.Field that is wrapped by this
132      * JavaField.
133      * @return the java.lang.reflect.Field instance.
134      */
135     protected Field getField()
136     {
137         ensureInitializedField();
138         return this.field;
139     }
140 
141     /***
142      * Helper method to retrieve the java.lang.reflect.Field for the specified
143      * field name.
144      * @param clazz the Class instance of the declaring class or interface
145      * @param fieldName the field name
146      * @return the java.lang.reflect.Field for the specified field name.
147      */
148     public static Field getDeclaredFieldPrivileged(final Class clazz, 
149                                                    final String fieldName)
150     {
151         if ((clazz == null) || (fieldName == null))
152             return null;
153 
154         return (Field) AccessController.doPrivileged(
155             new PrivilegedAction() {
156                 public Object run () {
157                     try {
158                         return clazz.getDeclaredField(fieldName);
159                     }
160                     catch (SecurityException ex) {
161                         throw new ModelFatalException(
162                             msg.msg("EXC_CannotGetDeclaredField", //NOI18N
163                                     clazz.getName()), ex); 
164                     }
165                     catch (NoSuchFieldException ex) {
166                         return null; // do nothing, just return null
167                     }
168                 }
169             }
170             );
171     }
172 
173     /***
174      * Helper method to retrieve the declared java.lang.reflect.Field
175      * instances for the specified class.
176      * @param clazz the Class instance of the declaring class or interface
177      * @return the java.lang.reflect.Field instances for the declared fields
178      * of the specified class.
179      */
180     public static Field[] getDeclaredFieldsPrivileged(final Class clazz)
181     {
182         if (clazz == null)
183             return null;
184 
185         return (Field[]) AccessController.doPrivileged(
186             new PrivilegedAction() {
187                 public Object run () {
188                     try {
189                         return clazz.getDeclaredFields();
190                     }
191                     catch (SecurityException ex) {
192                         throw new ModelFatalException(
193                             msg.msg("EXC_CannotGetDeclaredFields", //NOI18N
194                                     clazz.getName()), ex); 
195                     }
196                 }
197             }
198             );
199     }
200 
201     // ===== Internal helper methods =====
202     
203     /***
204      * This method makes sure the reflection field is set.
205      */
206     protected void ensureInitializedField()
207     {
208         if (this.field == null) {
209             this.field = getDeclaredFieldPrivileged(
210                 ((BaseReflectionJavaType)getDeclaringClass()).getJavaClass(),
211                 getName());
212             if (field == null) {
213                 throw new ModelFatalException(msg.msg(
214                     "ERR_MissingFieldInstance", //NOI18N
215                     "BaseReflectionJavaField.ensureInitializedField", getName())); //NOI18N
216             }
217         }
218     }
219 
220 }