Skip to main content
summaryrefslogtreecommitdiffstats
blob: f1930c829c99d26df7e128d515ac019184d16faa (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
/*******************************************************************************
 * Copyright (c) 2005, 2010 Oracle. All rights reserved.
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0, which accompanies this distribution
 * and is available at http://www.eclipse.org/legal/epl-v10.html.
 * 
 * Contributors:
 *     Oracle - initial API and implementation
 ******************************************************************************/
package org.eclipse.jpt.common.core.internal.utility.jdt;

import java.lang.reflect.Modifier;

/**
 * Convenience methods for JPA-related queries concerning JDT objects.
 */
//TODO this needs to move because it is only used for JPA
public class JPTTools {

	// ********** type **********

	/**
	 * Return whether the specified type can be "persisted", i.e. marked as
	 * Entity, MappedSuperclass, Embeddable
	 */
	public static boolean typeIsPersistable(TypeAdapter typeAdapter) {
		if (typeAdapter.isInterface()) {
			return false;
		}
		if (typeAdapter.isAnnotation()) {
			return false;
		}
		if (typeAdapter.isEnum()) {
			return false;
		}
		if (typeAdapter.isLocal()) {
			return false;
		}
		if (typeAdapter.isAnonymous()) {
			return false;
		}
		if (typeAdapter.isPrimitive()) {
			return false;  // should never get here(?)
		}
		if (typeAdapter.isArray()) {
			return false;  // should never get here(?)
		}
		return true;
	}

	/**
	 * Queries needed to calculate whether a type is "persistable".
	 * Adapted to ITypeBinding and IType.
	 */
	public interface TypeAdapter {
		int getModifiers();
		boolean isAnnotation();
		boolean isAnonymous();
		boolean isArray();
		boolean isEnum();
		boolean isInterface();
		boolean isLocal();
		boolean isMember();
		boolean isPrimitive();
	}


	// ********** field **********

	/**
	 * Return whether the specified field may be "persisted".
	 * According to the spec, "All non-transient instance variables that are not 
	 * annotated with the Transient annotation are persistent."
	 */
	public static boolean fieldIsPersistable(FieldAdapter fieldAdapter) {
		int modifiers = fieldAdapter.getModifiers();
		if (Modifier.isStatic(modifiers)) {
			return false;
		}
		if (Modifier.isTransient(modifiers)) {
			return false;
		}
		return true;
	}

	/**
	 * Queries needed to calculate whether a field is "persistable".
	 * Adapted to IVariableBinding and IField.
	 */
	public interface FieldAdapter {
		/**
		 * Return the field's modifiers. We use these to check whether the
		 * field is static or transient.
		 */
		int getModifiers();
	}


	// ********** method **********

	/**
	 * Return whether the specified method is a "getter" method that
	 * represents a property that may be "persisted".
	 */
	public static boolean methodIsPersistablePropertyGetter(MethodAdapter methodAdapter) {
		if (methodHasInvalidModifiers(methodAdapter)) {
			return false;
		}
		if (methodAdapter.isConstructor()) {
			return false;
		}

		String returnTypeName = methodAdapter.getReturnTypeErasureName();
		if (returnTypeName == null) {
			return false;  // DOM method bindings can have a null name
		}
		if (returnTypeName.equals("void")) { //$NON-NLS-1$
			return false;
		}
		if (methodHasParameters(methodAdapter)) {
			return false;
		}

		String name = methodAdapter.getName();
		int beginIndex = 0;
		boolean booleanGetter = false;
		if (name.startsWith("is")) { //$NON-NLS-1$
			if (returnTypeName.equals("boolean")) { //$NON-NLS-1$
				beginIndex = 2;
			} else {
				return false;
			}
		} else if (name.startsWith("get")) { //$NON-NLS-1$
			beginIndex = 3;
			if (returnTypeName.equals("boolean")) { //$NON-NLS-1$
				booleanGetter = true;
			}
		} else {
			return false;
		}

		String capitalizedAttributeName = name.substring(beginIndex);
		// if the type has both methods:
		//     boolean isProperty()
		//     boolean getProperty()
		// then #isProperty() takes precedence and we ignore #getProperty();
		// but only having #getProperty() is OK too
		// (see the JavaBeans spec 1.01)
		if (booleanGetter && methodHasValidSiblingIsMethod(methodAdapter, capitalizedAttributeName)) {
			return false;  // since the type also defines #isProperty(), ignore #getProperty()
		}
		return methodHasValidSiblingSetMethod(methodAdapter, capitalizedAttributeName, returnTypeName);
	}

	/**
	 * Return whether the method's modifiers prevent it
	 * from being a getter or setter for a "persistent" property.
	 */
	private static boolean methodHasInvalidModifiers(SimpleMethodAdapter methodAdapter) {
		int modifiers = methodAdapter.getModifiers();
		if (Modifier.isStatic(modifiers)) {
			return true;
		}
		return false;
	}

	private static boolean methodHasParameters(MethodAdapter methodAdapter) {
		return methodAdapter.getParametersLength() != 0;
	}

	/**
	 * Return whether the method has a sibling "is" method for the specified
	 * property and that method is valid for a "persistable" property.
	 * Pre-condition: the method is a "boolean getter" (e.g. 'public boolean getProperty()');
	 * this prevents us from returning true when the method itself is an
	 * "is" method.
	 */
	private static boolean methodHasValidSiblingIsMethod(MethodAdapter methodAdapter, String capitalizedAttributeName) {
		SimpleMethodAdapter isMethodAdapter = methodAdapter.getSibling("is" + capitalizedAttributeName); //$NON-NLS-1$
		return methodIsValidSibling(isMethodAdapter, "boolean"); //$NON-NLS-1$
	}

	/**
	 * Return whether the method has a sibling "set" method
	 * and that method is valid for a "persistable" property.
	 */
	private static boolean methodHasValidSiblingSetMethod(MethodAdapter methodAdapter, String capitalizedAttributeName, String parameterTypeErasureName) {
		SimpleMethodAdapter setMethodAdapter = methodAdapter.getSibling("set" + capitalizedAttributeName, parameterTypeErasureName); //$NON-NLS-1$
		return methodIsValidSibling(setMethodAdapter, "void"); //$NON-NLS-1$
	}

	/**
	 * Return whether the specified method is a valid sibling with the
	 * specified return type.
	 */
	private static boolean methodIsValidSibling(SimpleMethodAdapter methodAdapter, String returnTypeName) {
		if (methodAdapter == null) {
			return false;
		}
		if (methodHasInvalidModifiers(methodAdapter)) {
			return false;
		}
		if (methodAdapter.isConstructor()) {
			return false;
		}
		String rtName = methodAdapter.getReturnTypeErasureName();
		if (rtName == null) {
			return false;  // DOM method bindings can have a null name
		}
		return rtName.equals(returnTypeName);
	}

	/**
	 * Queries needed to calculate whether a method is "persistable".
	 * Adapted to IMethodBinding and IMethod.
	 */
	public interface SimpleMethodAdapter {
		/**
		 * Return the method's modifiers.
		 * We use these to check whether the method is static, final, etc.
		 */
		int getModifiers();

		/**
		 * Return the name of the method's return type erasure.
		 * We use this to check for
		 *   - boolean getters
		 *   - void return types
		 *   - matching getters and setters
		 */
		String getReturnTypeErasureName();

		/**
		 * Return whether the method is a constructor.
		 */
		boolean isConstructor();
	}

	/**
	 * Queries needed to calculate whether a method is "persistable".
	 * Adapted to IMethodBinding and IMethod.
	 */
	public interface MethodAdapter extends SimpleMethodAdapter {
		/**
		 * Return the method's name.
		 * We use this to determine
		 *   - whether the method is a "getter"
		 *   - the property name implied by the getter's name
		 */
		String getName();

		/**
		 * Return the number of paramters declared by the method.
		 * We use this to determine whether the method is a "getter".
		 */
		int getParametersLength();

		/**
		 * Return the method's "sibling" with the specified name and no parameters.
		 * We use this to find an "is" boolean getter that would take precedence
		 * over a "get" boolean getter.
		 */
		SimpleMethodAdapter getSibling(String name);

		/**
		 * Return the method's "sibling" with the specified name and single parameter.
		 * We use this to find a matching "setter" for a possible "getter".
		 */
		SimpleMethodAdapter getSibling(String name, String parameterTypeErasureName);
	}


	// ********** suppressed constructor **********

	/**
	 * Suppress default constructor, ensuring non-instantiability.
	 */
	private JPTTools() {
		super();
		throw new UnsupportedOperationException();
	}

}

Back to the top