blob: 328b806442d7297b84e98c1524185e70f47d614a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2009 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.core.internal.utility.jdt;
import java.lang.reflect.Modifier;
import java.util.Iterator;
import org.eclipse.jpt.core.resource.java.AccessType;
import org.eclipse.jpt.core.resource.java.JavaResourcePersistentAttribute;
import org.eclipse.jpt.core.resource.java.JavaResourcePersistentType;
/**
* Convenience methods for JPA-related queries concerning JDT objects.
*/
public class JPTTools {
// ********** type **********
/**
* Return whether the specified type can be "persisted", i.e. marked as
* Entity, MappedSuperclass, Embeddable
*/
// TODO check for no-arg constructor (or should that just be validation?)
// TODO move other checks to validation (e.g. 'final', 'static')?
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(?)
}
int modifiers = typeAdapter.getModifiers();
if (Modifier.isFinal(modifiers)) {
return false;
}
if (typeAdapter.isMember()) {
if ( ! Modifier.isStatic(modifiers)) {
return false;
}
}
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 {
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.getReturnTypeName();
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(MethodAdapter methodAdapter) {
int modifiers = methodAdapter.getModifiers();
if (Modifier.isStatic(modifiers)) {
return true;
}
if (Modifier.isFinal(modifiers)) {
return true;
}
if ( ! (Modifier.isPublic(modifiers) || Modifier.isProtected(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) {
MethodAdapter 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 returnTypeName) {
MethodAdapter setMethodAdapter = methodAdapter.getSibling("set" + capitalizedAttributeName, returnTypeName); //$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(MethodAdapter methodAdapter, String returnTypeName) {
if (methodAdapter == null) {
return false;
}
if (methodHasInvalidModifiers(methodAdapter)) {
return false;
}
if (methodAdapter.isConstructor()) {
return false;
}
String rtName = methodAdapter.getReturnTypeName();
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 MethodAdapter {
String getName();
int getModifiers();
String getReturnTypeName();
boolean isConstructor();
int getParametersLength();
MethodAdapter getSibling(String name);
MethodAdapter getSibling(String name, String parameterTypeName);
}
// ********** Access type **********
/**
* Return the AccessType currently implied by the Java source code
* or class file:
* - if only Fields are annotated => FIELD
* - if only Properties are annotated => PROPERTY
* - if both Fields and Properties are annotated => FIELD
* - if nothing is annotated
* - and fields exist => FIELD
* - and properties exist, but no fields exist => PROPERTY
* - and neither fields nor properties exist => null at this level (FIELD in the context model)
*/
public static AccessType buildAccess(JavaResourcePersistentType jrpType) {
boolean hasPersistableFields = false;
for (Iterator<JavaResourcePersistentAttribute> stream = jrpType.persistableFields(); stream.hasNext(); ) {
hasPersistableFields = true;
if (stream.next().hasAnyPersistenceAnnotations()) {
// any field is annotated => FIELD
return AccessType.FIELD;
}
}
boolean hasPersistableProperties = false;
for (Iterator<JavaResourcePersistentAttribute> stream = jrpType.persistableProperties(); stream.hasNext(); ) {
hasPersistableProperties = true;
if (stream.next().hasAnyPersistenceAnnotations()) {
// none of the fields are annotated and a getter is annotated => PROPERTY
return AccessType.PROPERTY;
}
}
if (hasPersistableProperties && ! hasPersistableFields) {
return AccessType.PROPERTY;
}
// if no annotations exist, access is null at the resource model level
return null;
}
// ********** suppressed constructor **********
/**
* Suppress default constructor, ensuring non-instantiability.
*/
private JPTTools() {
super();
throw new UnsupportedOperationException();
}
}