package org.springframework.roo.addon.jpa.activerecord;
import static org.springframework.roo.model.JavaType.INT_PRIMITIVE;
import static org.springframework.roo.model.JdkJavaType.LIST;
import static org.springframework.roo.model.JpaJavaType.ENTITY_MANAGER;
import static org.springframework.roo.model.JpaJavaType.PERSISTENCE_CONTEXT;
import static org.springframework.roo.model.SpringJavaType.PROPAGATION;
import static org.springframework.roo.model.SpringJavaType.TRANSACTIONAL;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.springframework.roo.classpath.PhysicalTypeIdentifierNamingUtils;
import org.springframework.roo.classpath.PhysicalTypeMetadata;
import org.springframework.roo.classpath.customdata.CustomDataKeys;
import org.springframework.roo.classpath.details.FieldMetadata;
import org.springframework.roo.classpath.details.FieldMetadataBuilder;
import org.springframework.roo.classpath.details.MemberFindingUtils;
import org.springframework.roo.classpath.details.MethodMetadata;
import org.springframework.roo.classpath.details.MethodMetadataBuilder;
import org.springframework.roo.classpath.details.annotations.AnnotatedJavaType;
import org.springframework.roo.classpath.details.annotations.AnnotationMetadataBuilder;
import org.springframework.roo.classpath.itd.AbstractItdTypeDetailsProvidingMetadataItem;
import org.springframework.roo.classpath.itd.InvocableMemberBodyBuilder;
import org.springframework.roo.metadata.MetadataIdentificationUtils;
import org.springframework.roo.model.DataType;
import org.springframework.roo.model.EnumDetails;
import org.springframework.roo.model.JavaSymbolName;
import org.springframework.roo.model.JavaType;
import org.springframework.roo.project.LogicalPath;
/**
* Metadata for a type annotated with {@link RooJpaActiveRecord}.
*
* @author Ben Alex
* @author Stefan Schmidt
* @author Alan Stewart
* @since 1.0
*/
public class JpaActiveRecordMetadata extends
AbstractItdTypeDetailsProvidingMetadataItem {
private static final JavaType COUNT_RETURN_TYPE = JavaType.LONG_PRIMITIVE;
private static final String ENTITY_MANAGER_METHOD_NAME = "entityManager";
private static final String PROVIDES_TYPE_STRING = JpaActiveRecordMetadata.class
.getName();
private static final String PROVIDES_TYPE = MetadataIdentificationUtils
.create(PROVIDES_TYPE_STRING);
private JpaCrudAnnotationValues crudAnnotationValues;
private MethodMetadata entityManagerMethod;
private String entityName;
private MethodMetadata findMethod;
private FieldMetadata identifierField;
private boolean isGaeEnabled;
private JpaActiveRecordMetadata parent;
private String plural;
/**
* Constructor
*
* @param metadataIdentificationString (required)
* @param aspectName (required)
* @param governorPhysicalTypeMetadata (required)
* @param parent can be <code>null</code>
* @param projectMetadata (required)
* @param crudAnnotationValues the CRUD-related annotation values (required)
* @param plural the plural form of the entity (required)
* @param identifierField the entity's identifier field (required)
* @param entityName the JPA entity name (required)
*/
public JpaActiveRecordMetadata(final String metadataIdentificationString,
final JavaType aspectName,
final PhysicalTypeMetadata governorPhysicalTypeMetadata,
final JpaActiveRecordMetadata parent,
final JpaCrudAnnotationValues crudAnnotationValues,
final String plural, final FieldMetadata identifierField,
final String entityName, final boolean isGaeEnabled) {
super(metadataIdentificationString, aspectName,
governorPhysicalTypeMetadata);
Validate.isTrue(
isValid(metadataIdentificationString),
"Metadata identification string '%s' does not appear to be a valid",
metadataIdentificationString);
Validate.notNull(crudAnnotationValues,
"CRUD-related annotation values required");
Validate.notNull(identifierField, "Identifier required for '%s'",
metadataIdentificationString);
Validate.notBlank(entityName, "Entity name required for '%s'",
metadataIdentificationString);
Validate.notBlank(plural, "Plural required for '%s'",
metadataIdentificationString);
if (!isValid()) {
return;
}
this.crudAnnotationValues = crudAnnotationValues;
this.entityName = entityName;
this.identifierField = identifierField;
this.isGaeEnabled = isGaeEnabled;
this.parent = parent;
this.plural = StringUtils.capitalize(plural);
// Determine the entity's "entityManager" field, which is guaranteed to
// be accessible to the ITD.
builder.addField(getEntityManagerField());
// Add static methods
setEntityManagerMethod();
builder.addMethod(getCountMethod());
builder.addMethod(getFindAllMethod());
setFindMethod();
builder.addMethod(getFindEntriesMethod());
// Add helper methods
builder.addMethod(getPersistMethod());
builder.addMethod(getRemoveMethod());
builder.addMethod(getFlushMethod());
builder.addMethod(getClearMethod());
builder.addMethod(getMergeMethod());
builder.putCustomData(CustomDataKeys.DYNAMIC_FINDER_NAMES,
getDynamicFinders());
// Create a representation of the desired output ITD
itdTypeDetails = builder.build();
}
public FieldMetadata getIdentifierField() {
return identifierField;
}
public void setIdentifierField(FieldMetadata identifierField) {
this.identifierField = identifierField;
}
public static String createIdentifier(final JavaType javaType,
final LogicalPath path) {
return PhysicalTypeIdentifierNamingUtils.createIdentifier(
PROVIDES_TYPE_STRING, javaType, path);
}
public static JavaType getJavaType(final String metadataIdentificationString) {
return PhysicalTypeIdentifierNamingUtils.getJavaType(
PROVIDES_TYPE_STRING, metadataIdentificationString);
}
public static String getMetadataIdentifierType() {
return PROVIDES_TYPE;
}
public static LogicalPath getPath(final String metadataIdentificationString) {
return PhysicalTypeIdentifierNamingUtils.getPath(PROVIDES_TYPE_STRING,
metadataIdentificationString);
}
public static boolean isValid(final String metadataIdentificationString) {
return PhysicalTypeIdentifierNamingUtils.isValid(PROVIDES_TYPE_STRING,
metadataIdentificationString);
}
/**
* @return the dynamic, custom finders (never returns null, but may return
* an empty list)
*/
public List<String> getDynamicFinders() {
if (crudAnnotationValues.getFinders() == null) {
return Collections.emptyList();
}
return Arrays.asList(crudAnnotationValues.getFinders());
}
/**
* Locates the entity manager field that should be used.
* <p>
* If a parent is defined, it must provide the field unless a persistent
* unit name is supplied on the child entity.
* <p>
* We generally expect the field to be named "entityManager" and be of type
* javax.persistence.EntityManager. We also require it to be public or
* protected, and annotated with @PersistenceContext. If there is an
* existing field which doesn't meet these latter requirements, we add an
* underscore prefix to the "entityManager" name and try again, until such
* time as we come up with a unique name that either meets the requirements
* or the name is not used and we will create it.
*
* @return the entity manager field (never returns null)
*/
public FieldMetadata getEntityManagerField() {
if (parent != null
&& StringUtils.isBlank(crudAnnotationValues
.getPersistenceUnit())) {
// The parent is required to guarantee this is available
return parent.getEntityManagerField();
}
// Need to locate it ourself
int index = -1;
while (true) {
// Compute the required field name
index++;
final JavaSymbolName fieldSymbolName = new JavaSymbolName(
StringUtils.repeat("_", index) + "entityManager");
final FieldMetadata candidate = governorTypeDetails
.getField(fieldSymbolName);
if (candidate != null) {
// Verify if candidate is suitable
if (!Modifier.isPublic(candidate.getModifier())
&& !Modifier.isProtected(candidate.getModifier())
&& Modifier.TRANSIENT != candidate.getModifier()) {
// Candidate is not public and not protected and not simply
// a transient field (in which case subclasses
// will see the inherited field), so any subsequent
// subclasses won't be able to see it. Give up!
continue;
}
if (!candidate.getFieldType().equals(ENTITY_MANAGER)) {
// Candidate isn't an EntityManager, so give up
continue;
}
if (MemberFindingUtils.getAnnotationOfType(
candidate.getAnnotations(), PERSISTENCE_CONTEXT) == null) {
// Candidate doesn't have a PersistenceContext annotation,
// so give up
continue;
}
// If we got this far, we found a valid candidate
return candidate;
}
// Candidate not found, so let's create one
final List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
final AnnotationMetadataBuilder annotationBuilder = new AnnotationMetadataBuilder(
PERSISTENCE_CONTEXT);
if (StringUtils.isNotBlank(crudAnnotationValues
.getPersistenceUnit())) {
annotationBuilder.addStringAttribute("unitName",
crudAnnotationValues.getPersistenceUnit());
}
annotations.add(annotationBuilder);
return new FieldMetadataBuilder(getId(), Modifier.TRANSIENT,
annotations, fieldSymbolName, ENTITY_MANAGER).build();
}
}
/**
* @return the static utility entityManager() method used by other methods
* to obtain entity manager and available as a utility for user code
* (never returns nulls)
*/
public MethodMetadata getEntityManagerMethod() {
return entityManagerMethod;
}
/**
* Returns the JPA name of this entity.
*
* @return a non-<code>null</code> name (might be empty)
*/
public String getEntityName() {
return entityName;
}
/**
* @return the find (by ID) method (may return null)
*/
public MethodMetadata getFindMethod() {
return findMethod;
}
/**
* @return the pluralised name (never returns null or an empty string)
*/
public String getPlural() {
return plural;
}
@Override
public String toString() {
final ToStringBuilder builder = new ToStringBuilder(this);
builder.append("identifier", getId());
builder.append("valid", valid);
builder.append("aspectName", aspectName);
builder.append("destinationType", destination);
builder.append("finders", crudAnnotationValues.getFinders());
builder.append("governor", governorPhysicalTypeMetadata.getId());
builder.append("itdTypeDetails", itdTypeDetails);
return builder.toString();
}
private void addTransactionalAnnotation(
final List<AnnotationMetadataBuilder> annotations) {
addTransactionalAnnotation(annotations, false);
}
private void addTransactionalAnnotation(
final List<AnnotationMetadataBuilder> annotations,
final boolean isPersistMethod) {
final AnnotationMetadataBuilder transactionalBuilder = new AnnotationMetadataBuilder(
TRANSACTIONAL);
if (StringUtils
.isNotBlank(crudAnnotationValues.getTransactionManager())) {
transactionalBuilder.addStringAttribute("value",
crudAnnotationValues.getTransactionManager());
}
if (isGaeEnabled && isPersistMethod) {
transactionalBuilder.addEnumAttribute("propagation",
new EnumDetails(PROPAGATION, new JavaSymbolName(
"REQUIRES_NEW")));
}
annotations.add(transactionalBuilder);
}
/**
* @return the clear method (never returns null)
*/
private MethodMetadataBuilder getClearMethod() {
if (parent != null) {
final MethodMetadataBuilder found = parent.getClearMethod();
if (found != null) {
return found;
}
}
if ("".equals(crudAnnotationValues.getClearMethod())) {
return null;
}
return getDelegateMethod(
new JavaSymbolName(crudAnnotationValues.getClearMethod()),
"clear");
}
/**
* Finds (creating if necessary) the method that counts entities of this
* type
*
* @return the count method (never null)
*/
private MethodMetadata getCountMethod() {
// Method definition to find or build
final JavaSymbolName methodName = new JavaSymbolName(
crudAnnotationValues.getCountMethod() + plural);
final JavaType[] parameterTypes = {};
final List<JavaSymbolName> parameterNames = Collections
.<JavaSymbolName> emptyList();
// Locate user-defined method
final MethodMetadata userMethod = getGovernorMethod(methodName,
parameterTypes);
if (userMethod != null) {
Validate.isTrue(userMethod.getReturnType()
.equals(COUNT_RETURN_TYPE),
"Method '%s' on %s must return '%s'", methodName,
destination,
COUNT_RETURN_TYPE.getNameIncludingTypeParameters() + "'");
return userMethod;
}
// Create method
final List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
if (isGaeEnabled) {
addTransactionalAnnotation(annotations);
}
final InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();
if (isGaeEnabled) {
bodyBuilder.appendFormalLine("return "
+ getFindAllMethod().getMethodName() + "().size();");
}
else {
bodyBuilder.appendFormalLine("return " + ENTITY_MANAGER_METHOD_NAME
+ "().createQuery(\"SELECT COUNT(o) FROM " + entityName
+ " o\", Long.class).getSingleResult();");
}
final MethodMetadataBuilder methodBuilder = new MethodMetadataBuilder(
getId(), Modifier.PUBLIC | Modifier.STATIC, methodName,
COUNT_RETURN_TYPE,
AnnotatedJavaType.convertFromJavaTypes(parameterTypes),
parameterNames, bodyBuilder);
methodBuilder.setAnnotations(annotations);
return methodBuilder.build();
}
private MethodMetadataBuilder getDelegateMethod(
final JavaSymbolName methodName, final String methodDelegateName) {
// Method definition to find or build
final JavaType[] parameterTypes = {};
// Locate user-defined method
final MethodMetadata userMethod = getGovernorMethod(methodName,
parameterTypes);
if (userMethod != null) {
return new MethodMetadataBuilder(userMethod);
}
// Create the method
final List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
final InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();
// Address non-injected entity manager field
final MethodMetadata entityManagerMethod = getEntityManagerMethod();
Validate.notNull(entityManagerMethod,
"Entity manager method should not have returned null");
// Use the getEntityManager() method to acquire an entity manager (the
// method will throw an exception if it cannot be acquired)
final String entityManagerFieldName = getEntityManagerField()
.getFieldName().getSymbolName();
bodyBuilder.appendFormalLine("if (this." + entityManagerFieldName
+ " == null) this." + entityManagerFieldName + " = "
+ entityManagerMethod.getMethodName().getSymbolName() + "();");
JavaType returnType = JavaType.VOID_PRIMITIVE;
if ("flush".equals(methodDelegateName)) {
addTransactionalAnnotation(annotations);
bodyBuilder.appendFormalLine("this." + entityManagerFieldName
+ ".flush();");
}
else if ("clear".equals(methodDelegateName)) {
addTransactionalAnnotation(annotations);
bodyBuilder.appendFormalLine("this." + entityManagerFieldName
+ ".clear();");
}
else if ("merge".equals(methodDelegateName)) {
addTransactionalAnnotation(annotations);
returnType = new JavaType(destination.getSimpleTypeName());
bodyBuilder.appendFormalLine(destination.getSimpleTypeName()
+ " merged = this." + entityManagerFieldName
+ ".merge(this);");
bodyBuilder.appendFormalLine("this." + entityManagerFieldName
+ ".flush();");
bodyBuilder.appendFormalLine("return merged;");
}
else if ("remove".equals(methodDelegateName)) {
addTransactionalAnnotation(annotations);
bodyBuilder.appendFormalLine("if (this." + entityManagerFieldName
+ ".contains(this)) {");
bodyBuilder.indent();
bodyBuilder.appendFormalLine("this." + entityManagerFieldName
+ ".remove(this);");
bodyBuilder.indentRemove();
bodyBuilder.appendFormalLine("} else {");
bodyBuilder.indent();
bodyBuilder.appendFormalLine(destination.getSimpleTypeName()
+ " attached = " + destination.getSimpleTypeName() + "."
+ getFindMethod().getMethodName().getSymbolName()
+ "(this." + identifierField.getFieldName().getSymbolName()
+ ");");
bodyBuilder.appendFormalLine("this." + entityManagerFieldName
+ ".remove(attached);");
bodyBuilder.indentRemove();
bodyBuilder.appendFormalLine("}");
}
else {
// Persist
addTransactionalAnnotation(annotations, true);
bodyBuilder.appendFormalLine("this." + entityManagerFieldName + "."
+ methodDelegateName + "(this);");
}
final MethodMetadataBuilder methodBuilder = new MethodMetadataBuilder(
getId(), Modifier.PUBLIC, methodName, returnType,
AnnotatedJavaType.convertFromJavaTypes(parameterTypes),
new ArrayList<JavaSymbolName>(), bodyBuilder);
methodBuilder.setAnnotations(annotations);
return methodBuilder;
}
/**
* @return the find all method (may return null)
*/
private MethodMetadata getFindAllMethod() {
if ("".equals(crudAnnotationValues.getFindAllMethod())) {
return null;
}
// Method definition to find or build
final JavaSymbolName methodName = new JavaSymbolName(
crudAnnotationValues.getFindAllMethod() + plural);
final JavaType[] parameterTypes = {};
final List<JavaSymbolName> parameterNames = new ArrayList<JavaSymbolName>();
final JavaType returnType = new JavaType(
LIST.getFullyQualifiedTypeName(), 0, DataType.TYPE, null,
Arrays.asList(destination));
// Locate user-defined method
final MethodMetadata userMethod = getGovernorMethod(methodName,
parameterTypes);
if (userMethod != null) {
Validate.isTrue(
userMethod.getReturnType().equals(returnType),
"Method '" + methodName + "' on '" + destination
+ "' must return '"
+ returnType.getNameIncludingTypeParameters() + "'");
return userMethod;
}
// Create method
final List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
if (isGaeEnabled) {
addTransactionalAnnotation(annotations);
}
final InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();
bodyBuilder.appendFormalLine("return " + ENTITY_MANAGER_METHOD_NAME
+ "().createQuery(\"SELECT o FROM " + entityName + " o\", "
+ destination.getSimpleTypeName() + ".class).getResultList();");
final MethodMetadataBuilder methodBuilder = new MethodMetadataBuilder(
getId(), Modifier.PUBLIC | Modifier.STATIC, methodName,
returnType,
AnnotatedJavaType.convertFromJavaTypes(parameterTypes),
parameterNames, bodyBuilder);
methodBuilder.setAnnotations(annotations);
return methodBuilder.build();
}
/**
* @return the find entries method (may return null)
*/
private MethodMetadata getFindEntriesMethod() {
if ("".equals(crudAnnotationValues.getFindEntriesMethod())) {
return null;
}
// Method definition to find or build
final JavaSymbolName methodName = new JavaSymbolName(
crudAnnotationValues.getFindEntriesMethod()
+ destination.getSimpleTypeName() + "Entries");
final JavaType[] parameterTypes = { INT_PRIMITIVE, INT_PRIMITIVE };
final List<JavaSymbolName> parameterNames = Arrays.asList(
new JavaSymbolName("firstResult"), new JavaSymbolName(
"maxResults"));
final JavaType returnType = new JavaType(
LIST.getFullyQualifiedTypeName(), 0, DataType.TYPE, null,
Arrays.asList(destination));
// Locate user-defined method
final MethodMetadata userMethod = getGovernorMethod(methodName,
parameterTypes);
if (userMethod != null) {
Validate.isTrue(
userMethod.getReturnType().equals(returnType),
"Method '" + methodName + "' on '" + destination
+ "' must return '"
+ returnType.getNameIncludingTypeParameters() + "'");
return userMethod;
}
// Create method
final List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
if (isGaeEnabled) {
addTransactionalAnnotation(annotations);
}
final InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();
bodyBuilder
.appendFormalLine("return "
+ ENTITY_MANAGER_METHOD_NAME
+ "().createQuery(\"SELECT o FROM "
+ entityName
+ " o\", "
+ destination.getSimpleTypeName()
+ ".class).setFirstResult(firstResult).setMaxResults(maxResults).getResultList();");
final MethodMetadataBuilder methodBuilder = new MethodMetadataBuilder(
getId(), Modifier.PUBLIC | Modifier.STATIC, methodName,
returnType,
AnnotatedJavaType.convertFromJavaTypes(parameterTypes),
parameterNames, bodyBuilder);
methodBuilder.setAnnotations(annotations);
return methodBuilder.build();
}
/**
* @return the flush method (never returns null)
*/
private MethodMetadataBuilder getFlushMethod() {
if (parent != null) {
final MethodMetadataBuilder found = parent.getFlushMethod();
if (found != null) {
return found;
}
}
if ("".equals(crudAnnotationValues.getFlushMethod())) {
return null;
}
return getDelegateMethod(
new JavaSymbolName(crudAnnotationValues.getFlushMethod()),
"flush");
}
/**
* @return the merge method (may return null)
*/
private MethodMetadataBuilder getMergeMethod() {
if ("".equals(crudAnnotationValues.getMergeMethod())) {
return null;
}
return getDelegateMethod(
new JavaSymbolName(crudAnnotationValues.getMergeMethod()),
"merge");
}
/**
* @return the persist method (may return null)
*/
private MethodMetadataBuilder getPersistMethod() {
if (parent != null) {
final MethodMetadataBuilder found = parent.getPersistMethod();
if (found != null) {
return found;
}
}
if ("".equals(crudAnnotationValues.getPersistMethod())) {
return null;
}
return getDelegateMethod(
new JavaSymbolName(crudAnnotationValues.getPersistMethod()),
"persist");
}
/**
* @return the remove method (may return null)
*/
private MethodMetadataBuilder getRemoveMethod() {
if (parent != null) {
final MethodMetadataBuilder found = parent.getRemoveMethod();
if (found != null) {
return found;
}
}
if ("".equals(crudAnnotationValues.getRemoveMethod())) {
return null;
}
return getDelegateMethod(
new JavaSymbolName(crudAnnotationValues.getRemoveMethod()),
"remove");
}
private void setEntityManagerMethod() {
if (parent != null) {
// The parent is required to guarantee this is available
entityManagerMethod = parent.getEntityManagerMethod();
return;
}
// Method definition to find or build
final JavaSymbolName methodName = new JavaSymbolName(
ENTITY_MANAGER_METHOD_NAME);
final JavaType[] parameterTypes = {};
final JavaType returnType = ENTITY_MANAGER;
// Locate user-defined method
final MethodMetadata userMethod = getGovernorMethod(methodName,
parameterTypes);
if (userMethod != null) {
Validate.isTrue(
userMethod.getReturnType().equals(returnType),
"Method '" + methodName + "' on '" + destination
+ "' must return '"
+ returnType.getNameIncludingTypeParameters() + "'");
entityManagerMethod = userMethod;
return;
}
// Create method
final InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();
if (Modifier.isAbstract(governorTypeDetails.getModifier())) {
// Create an anonymous inner class that extends the abstract class
// (no-arg constructor is available as this is a JPA entity)
bodyBuilder.appendFormalLine(ENTITY_MANAGER
.getNameIncludingTypeParameters(false,
builder.getImportRegistrationResolver())
+ " em = new " + destination.getSimpleTypeName() + "() {");
// Handle any abstract methods in this class
bodyBuilder.indent();
for (final MethodMetadata method : governorTypeDetails.getMethods()) {
if (Modifier.isAbstract(method.getModifier())) {
final StringBuilder params = new StringBuilder();
int i = -1;
final List<AnnotatedJavaType> types = method
.getParameterTypes();
for (final JavaSymbolName name : method.getParameterNames()) {
i++;
if (i > 0) {
params.append(", ");
}
final AnnotatedJavaType type = types.get(i);
params.append(type.toString()).append(" ").append(name);
}
final int newModifier = method.getModifier()
- Modifier.ABSTRACT;
bodyBuilder.appendFormalLine(Modifier.toString(newModifier)
+ " "
+ method.getReturnType()
.getNameIncludingTypeParameters() + " "
+ method.getMethodName().getSymbolName() + "("
+ params.toString() + ") {");
bodyBuilder.indent();
bodyBuilder
.appendFormalLine("throw new UnsupportedOperationException();");
bodyBuilder.indentRemove();
bodyBuilder.appendFormalLine("}");
}
}
bodyBuilder.indentRemove();
bodyBuilder.appendFormalLine("}."
+ getEntityManagerField().getFieldName().getSymbolName()
+ ";");
}
else {
// Instantiate using the no-argument constructor (we know this is
// available as the entity must comply with the JPA no-arg
// constructor requirement)
bodyBuilder.appendFormalLine(ENTITY_MANAGER
.getNameIncludingTypeParameters(false,
builder.getImportRegistrationResolver())
+ " em = new "
+ destination.getSimpleTypeName()
+ "()."
+ getEntityManagerField().getFieldName().getSymbolName()
+ ";");
}
bodyBuilder
.appendFormalLine("if (em == null) throw new IllegalStateException(\"Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)\");");
bodyBuilder.appendFormalLine("return em;");
final int modifier = Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL;
final MethodMetadataBuilder methodBuilder = new MethodMetadataBuilder(
getId(), modifier, methodName, returnType,
AnnotatedJavaType.convertFromJavaTypes(parameterTypes),
new ArrayList<JavaSymbolName>(), bodyBuilder);
builder.addMethod(methodBuilder);
entityManagerMethod = methodBuilder.build();
}
/**
* @return the find (by ID) method (may return null)
*/
private void setFindMethod() {
if ("".equals(crudAnnotationValues.getFindMethod())) {
return;
}
// Method definition to find or build
final String idFieldName = identifierField.getFieldName()
.getSymbolName();
final JavaSymbolName methodName = new JavaSymbolName(
crudAnnotationValues.getFindMethod()
+ destination.getSimpleTypeName());
final JavaType parameterType = identifierField.getFieldType();
final List<JavaSymbolName> parameterNames = Arrays
.asList(new JavaSymbolName(idFieldName));
final JavaType returnType = destination;
// Locate user-defined method
final MethodMetadata userMethod = getGovernorMethod(methodName,
parameterType);
if (userMethod != null) {
Validate.isTrue(
userMethod.getReturnType().equals(returnType),
"Method '" + methodName + "' on '" + returnType
+ "' must return '"
+ returnType.getNameIncludingTypeParameters() + "'");
findMethod = userMethod;
return;
}
// Create method
final List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
if (isGaeEnabled) {
addTransactionalAnnotation(annotations);
}
final InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();
if (JavaType.STRING.equals(identifierField.getFieldType())) {
bodyBuilder.appendFormalLine("if (" + idFieldName + " == null || "
+ idFieldName + ".length() == 0) return null;");
}
else if (!identifierField.getFieldType().isPrimitive()) {
bodyBuilder.appendFormalLine("if (" + idFieldName
+ " == null) return null;");
}
bodyBuilder.appendFormalLine("return " + ENTITY_MANAGER_METHOD_NAME
+ "().find(" + returnType.getSimpleTypeName() + ".class, "
+ idFieldName + ");");
final MethodMetadataBuilder methodBuilder = new MethodMetadataBuilder(
getId(), Modifier.PUBLIC | Modifier.STATIC, methodName,
returnType,
AnnotatedJavaType.convertFromJavaTypes(parameterType),
parameterNames, bodyBuilder);
methodBuilder.setAnnotations(annotations);
builder.addMethod(methodBuilder);
findMethod = methodBuilder.build();
}
}