KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cayenne > jpa > map > JpaClassDescriptor


1 /*****************************************************************
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. 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,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  ****************************************************************/

19
20 package org.apache.cayenne.jpa.map;
21
22 import java.lang.reflect.Field JavaDoc;
23 import java.lang.reflect.Member JavaDoc;
24 import java.lang.reflect.Method JavaDoc;
25 import java.lang.reflect.Modifier JavaDoc;
26 import java.util.ArrayList JavaDoc;
27 import java.util.Collection JavaDoc;
28 import java.util.HashMap JavaDoc;
29 import java.util.Map JavaDoc;
30 import java.util.regex.Matcher JavaDoc;
31 import java.util.regex.Pattern JavaDoc;
32
33 import org.apache.cayenne.enhancer.EnhancementHelper;
34
35 /**
36  * Provides information about a class relevant to JPA, such potential persistence fields,
37  * etc.
38  *
39  * @author Andrus Adamchik
40  */

41 public class JpaClassDescriptor {
42
43     private static final Pattern JavaDoc GETTER_PATTERN = Pattern
44             .compile("^(is|get)([A-Z])(.*)$");
45     private static final Pattern JavaDoc SETTER_PATTERN = Pattern.compile("^set([A-Z])(.*)$");
46
47     protected Collection JavaDoc<JpaPropertyDescriptor> fieldDescriptors;
48     protected Collection JavaDoc<JpaPropertyDescriptor> propertyDescriptors;
49     protected Class JavaDoc managedClass;
50     protected AccessType access;
51
52     public static String JavaDoc propertyNameForGetter(String JavaDoc getterName) {
53         Matcher JavaDoc getMatch = GETTER_PATTERN.matcher(getterName);
54         if (getMatch.matches()) {
55             return getMatch.group(2).toLowerCase() + getMatch.group(3);
56         }
57
58         return null;
59     }
60
61     public static String JavaDoc propertyNameForSetter(String JavaDoc setterName) {
62         Matcher JavaDoc setMatch = SETTER_PATTERN.matcher(setterName);
63
64         if (setMatch.matches()) {
65             return setMatch.group(1).toLowerCase() + setMatch.group(2);
66         }
67
68         return null;
69     }
70
71     public JpaClassDescriptor(Class JavaDoc managedClass) {
72         this.managedClass = managedClass;
73     }
74
75     public Class JavaDoc getManagedClass() {
76         return managedClass;
77     }
78
79     public AccessType getAccess() {
80         return access;
81     }
82
83     public void setAccess(AccessType access) {
84         this.access = access;
85     }
86
87     /**
88      * Returns descriptor matching the property name. If the underlying entity map uses
89      * FIELD access, a descritor is looked up in the list of class fields, if it uses
90      * PROPERTY access - descriptor is looked up in the list of class properties.
91      */

92     public JpaPropertyDescriptor getProperty(String JavaDoc name) {
93         if (getAccess() == AccessType.FIELD) {
94             for (JpaPropertyDescriptor d : getFieldDescriptors()) {
95                 if (name.equals(d.getName())) {
96                     return d;
97                 }
98             }
99         }
100         else if (getAccess() == AccessType.PROPERTY) {
101             for (JpaPropertyDescriptor d : getPropertyDescriptors()) {
102                 if (name.equals(d.getName())) {
103                     return d;
104                 }
105             }
106         }
107
108         return null;
109     }
110
111     /**
112      * Returns descriptor matching the property name. Note that entity map access type is
113      * ignored and instead field vs. property descriptor is determined from the member
114      * type.
115      */

116     public JpaPropertyDescriptor getPropertyForMember(Member JavaDoc classMember) {
117         if (classMember instanceof Field JavaDoc) {
118             for (JpaPropertyDescriptor d : getFieldDescriptors()) {
119                 if (d.getMember().equals(classMember)) {
120                     return d;
121                 }
122             }
123         }
124         else if (classMember instanceof Method JavaDoc) {
125             for (JpaPropertyDescriptor d : getPropertyDescriptors()) {
126                 if (d.getMember().equals(classMember)) {
127                     return d;
128                 }
129             }
130         }
131
132         return null;
133     }
134
135     public Collection JavaDoc<JpaPropertyDescriptor> getFieldDescriptors() {
136         if (fieldDescriptors == null) {
137             compileFields();
138         }
139
140         return fieldDescriptors;
141     }
142
143     /**
144      * Returns getters for public and protected methods that look like read/write bean
145      * properties, as those are potential persistent properties.
146      */

147     public Collection JavaDoc<JpaPropertyDescriptor> getPropertyDescriptors() {
148         if (propertyDescriptors == null) {
149             compileProperties();
150         }
151
152         return propertyDescriptors;
153     }
154
155     protected void compileFields() {
156
157         Field JavaDoc[] fields = managedClass.getDeclaredFields();
158         fieldDescriptors = new ArrayList JavaDoc<JpaPropertyDescriptor>(fields.length);
159
160         for (int i = 0; i < fields.length; i++) {
161
162             int modifiers = fields[i].getModifiers();
163             // skip transient fields (in a Java sense)
164
if (Modifier.isTransient(modifiers)) {
165                 continue;
166             }
167
168             // skip static fields
169
if (Modifier.isStatic(modifiers)) {
170                 continue;
171             }
172
173             // skip fields created by Cayenne enhancer
174
if (EnhancementHelper.isGeneratedField(fields[i].getName())) {
175                 continue;
176             }
177
178             fieldDescriptors.add(new JpaPropertyDescriptor(fields[i]));
179         }
180     }
181
182     protected void compileProperties() {
183
184         Map JavaDoc<String JavaDoc, PropertyTuple> properties = new HashMap JavaDoc<String JavaDoc, PropertyTuple>();
185
186         // per JPA spec, 2.1.1:
187
// The property accessor methods must be public or protected. When
188
// property-based access is used, the object/relational mapping annotations for
189
// the entity class annotate the getter property accessors.
190

191         // JPA Spec, 2.1.9.3, regarding non-entity superclasses:
192

193         // The non-entity superclass serves for inheritance of behavior only. The state of
194
// a non-entity superclass is not persistent. Any state inherited from non-entity
195
// superclasses is non-persistent in an inheriting entity class. This
196
// non-persistent state is not managed by the EntityManager, nor it is
197
// required to be retained across transactions. Any annotations on such
198
// superclasses are ignored.
199

200         Method JavaDoc[] methods = managedClass.getDeclaredMethods();
201         for (int i = 0; i < methods.length; i++) {
202
203             int modifiers = methods[i].getModifiers();
204             if (!Modifier.isProtected(modifiers) && !Modifier.isPublic(modifiers)) {
205                 continue;
206             }
207
208             String JavaDoc name = methods[i].getName();
209             Class JavaDoc[] parameters = methods[i].getParameterTypes();
210             Class JavaDoc returnType = methods[i].getReturnType();
211             boolean isVoid = Void.TYPE.equals(returnType);
212
213             if (!isVoid && parameters.length == 0) {
214                 String JavaDoc propertyName = propertyNameForGetter(name);
215
216                 if (propertyName != null) {
217                     String JavaDoc key = propertyName + ":" + returnType.getName();
218                     PropertyTuple t = properties.get(key);
219                     if (t == null) {
220                         t = new PropertyTuple();
221                         properties.put(key, t);
222                     }
223
224                     t.getter = methods[i];
225                     t.name = propertyName;
226                     continue;
227                 }
228             }
229
230             if (isVoid && parameters.length == 1) {
231                 String JavaDoc propertyName = propertyNameForSetter(name);
232
233                 if (propertyName != null) {
234
235                     String JavaDoc key = propertyName + ":" + parameters[0].getName();
236
237                     PropertyTuple t = properties.get(key);
238                     if (t == null) {
239                         t = new PropertyTuple();
240                         properties.put(key, t);
241                     }
242
243                     t.setter = methods[i];
244                 }
245             }
246         }
247
248         this.propertyDescriptors = new ArrayList JavaDoc<JpaPropertyDescriptor>(properties.size());
249
250         for (PropertyTuple t : properties.values()) {
251             if (t.getter != null && t.setter != null) {
252                 propertyDescriptors.add(new JpaPropertyDescriptor(t.getter, t.name));
253             }
254         }
255     }
256
257     final class PropertyTuple {
258
259         String JavaDoc name;
260         Method JavaDoc getter;
261         Method JavaDoc setter;
262     }
263 }
264
Popular Tags