package org.springframework.roo.addon.jpa.addon.dod; import static org.springframework.roo.model.JdkJavaType.LIST; import static org.springframework.roo.model.JdkJavaType.RANDOM; import static org.springframework.roo.model.JdkJavaType.SECURE_RANDOM; 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.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.builder.ToStringBuilder; import org.springframework.roo.addon.jpa.addon.entity.factories.JpaEntityFactoryMetadata; import org.springframework.roo.addon.jpa.annotations.dod.RooJpaDataOnDemand; import org.springframework.roo.classpath.PhysicalTypeIdentifierNamingUtils; import org.springframework.roo.classpath.PhysicalTypeMetadata; import org.springframework.roo.classpath.details.ConstructorMetadataBuilder; import org.springframework.roo.classpath.details.FieldMetadata; import org.springframework.roo.classpath.details.FieldMetadataBuilder; 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.details.comments.CommentStructure; import org.springframework.roo.classpath.details.comments.CommentStructure.CommentLocation; import org.springframework.roo.classpath.details.comments.JavadocComment; 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.JavaSymbolName; import org.springframework.roo.model.JavaType; import org.springframework.roo.model.JdkJavaType; import org.springframework.roo.model.JpaJavaType; import org.springframework.roo.model.Jsr303JavaType; import org.springframework.roo.project.LogicalPath; /** * Metadata for {@link RooJpaDataOnDemand}. * * @author Ben Alex * @author Stefan Schmidt * @author Alan Stewart * @author Greg Turnquist * @author Andrew Swan * @since 1.0 */ public class JpaDataOnDemandMetadata extends AbstractItdTypeDetailsProvidingMetadataItem { private static final String INDEX_VAR = "index"; private static final JavaSymbolName INDEX_SYMBOL = new JavaSymbolName(INDEX_VAR); private static final String OBJ_VAR = "obj"; private static final String PROVIDES_TYPE_STRING = JpaDataOnDemandMetadata.class.getName(); private static final String PROVIDES_TYPE = MetadataIdentificationUtils .create(PROVIDES_TYPE_STRING); private static final String ENTITY_MANAGER_VAR = "entityManager"; private static final String SIZE_VAR = "size"; private static final String FACTORY_VAR = "factory"; private static final JavaSymbolName FLUSH_METHOD_NAME = new JavaSymbolName("flush"); 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 getMetadataIdentiferType() { 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); } private JavaSymbolName dataFieldName; private EmbeddedIdHolder embeddedIdHolder; private JavaType entity; private MethodMetadata newTransientEntityMethod; private MethodMetadata randomPersistentEntityMethod; private JavaSymbolName rndFieldName; private JpaEntityFactoryMetadata entityFactoryMetadata; private MethodMetadata specificEntityMethod; private FieldMetadata sizeField; private JavaSymbolName sizeAccesorName; /** * Constructor * * @param identifier * @param aspectName * @param governorPhysicalTypeMetadata * @param annotationValues * @param entityFactoryMetadata */ public JpaDataOnDemandMetadata(final String identifier, final JavaType aspectName, final PhysicalTypeMetadata governorPhysicalTypeMetadata, final JpaDataOnDemandAnnotationValues annotationValues, final JpaEntityFactoryMetadata entityFactoryMetadata) { super(identifier, aspectName, governorPhysicalTypeMetadata); Validate.isTrue(isValid(identifier), "Metadata identification string '%s' does not appear to be a valid", identifier); Validate.notNull(annotationValues, "Annotation values required"); if (!isValid()) { return; } this.entityFactoryMetadata = entityFactoryMetadata; this.entity = annotationValues.getEntity(); // Add random field ensureGovernorHasField(getRndField()); // Add data field ensureGovernorHasField(getDataField()); // Add entity manager field ensureGovernorHasField(getEntityManagerField()); // Add size field this.sizeField = getSizeField(); ensureGovernorHasField(new FieldMetadataBuilder(this.sizeField)); this.sizeAccesorName = getAccessorMethod(this.sizeField).getMethodName(); // Add EntityFactory field related to this entity ensureGovernorHasField(getEntityFactoryField()); // Add constructors ensureGovernorHasConstructor(getConstructorWithEntityManager()); ensureGovernorHasConstructor(getConstructorWithEntityManagerAndSize()); // Add newRandomTransient method ensureGovernorHasMethod(new MethodMetadataBuilder(getNewRandomTransientEntityMethod())); // Add getSpecificEntity method ensureGovernorHasMethod(new MethodMetadataBuilder(getSpecificEntityMethod())); // Add getRandomEntity method ensureGovernorHasMethod(new MethodMetadataBuilder(getRandomPersistentEntityMethod())); // Add init method builder.addMethod(getInitMethod(annotationValues.getQuantity())); itdTypeDetails = builder.build(); } /** * Builds constructor with EntityManager argument. * * @return ConstructorMetadataBuilder for adding constructor to ITD */ private ConstructorMetadataBuilder getConstructorWithEntityManager() { ConstructorMetadataBuilder constructorBuilder = new ConstructorMetadataBuilder(getId()); InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder(); constructorBuilder.addParameter(ENTITY_MANAGER_VAR, JpaJavaType.ENTITY_MANAGER); // this(entityManager, 10); bodyBuilder.appendFormalLine(String.format("this(%1$s, 10);", ENTITY_MANAGER_VAR)); constructorBuilder.setModifier(Modifier.PUBLIC); constructorBuilder.setBodyBuilder(bodyBuilder); CommentStructure comment = new CommentStructure(); List<String> paramsInfo = new ArrayList<String>(); paramsInfo.add(ENTITY_MANAGER_VAR + " to persist entities"); JavadocComment javadocComment = new JavadocComment(String.format("Creates a new {@link %s}.", this.governorPhysicalTypeMetadata.getType().getSimpleTypeName()), paramsInfo, null, null); comment.addComment(javadocComment, CommentLocation.BEGINNING); constructorBuilder.setCommentStructure(comment); return constructorBuilder; } /** * Builds constructor with EntityManager and size arguments. * * @return {@link ConstructorMetadataBuilder} for adding constructor to ITD */ private ConstructorMetadataBuilder getConstructorWithEntityManagerAndSize() { ConstructorMetadataBuilder constructorBuilder = new ConstructorMetadataBuilder(getId()); InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder(); constructorBuilder.addParameter(ENTITY_MANAGER_VAR, JpaJavaType.ENTITY_MANAGER); constructorBuilder.addParameter(SIZE_VAR, JavaType.INT_PRIMITIVE); bodyBuilder.appendFormalLine(String.format("%1$s(%2$s);", getMutatorMethod(getEntityManagerField().build()).getMethodName(), ENTITY_MANAGER_VAR)); bodyBuilder.appendFormalLine(String.format("%1$s(%2$s);", getMutatorMethod(getSizeField()) .getMethodName(), SIZE_VAR)); constructorBuilder.setModifier(Modifier.PUBLIC); constructorBuilder.setBodyBuilder(bodyBuilder); CommentStructure comment = new CommentStructure(); List<String> paramsInfo = new ArrayList<String>(); paramsInfo.add(ENTITY_MANAGER_VAR + " to persist entities"); paramsInfo.add(SIZE_VAR + " the number of entities to create and persist initially."); JavadocComment javadocComment = new JavadocComment(String.format("Creates a new {@link %s}.", this.governorPhysicalTypeMetadata.getType().getSimpleTypeName()), paramsInfo, null, null); comment.addComment(javadocComment, CommentLocation.BEGINNING); constructorBuilder.setCommentStructure(comment); return constructorBuilder; } /** * @return the "data" field to use, which is either provided by the user or * produced on demand (never returns null) */ private FieldMetadataBuilder getDataField() { final List<JavaType> parameterTypes = Arrays.asList(entity); final JavaType listType = new JavaType(LIST.getFullyQualifiedTypeName(), 0, DataType.TYPE, null, parameterTypes); int index = -1; while (true) { // Compute the required field name index++; // The type parameters to be used by the field type final JavaSymbolName fieldName = new JavaSymbolName("data" + StringUtils.repeat("_", index)); dataFieldName = fieldName; final FieldMetadata candidate = governorTypeDetails.getField(fieldName); if (candidate != null) { // Verify if candidate is suitable if (!Modifier.isPrivate(candidate.getModifier())) { // Candidate is not private, so we might run into naming // clashes if someone subclasses this (therefore go onto the // next possible name) continue; } if (!candidate.getFieldType().equals(listType)) { // Candidate isn't a java.util.List<theEntity>, so it isn't // suitable // The equals method also verifies type params are present continue; } // If we got this far, we found a valid candidate // We don't check if there is a corresponding initializer, but // we assume the user knows what they're doing and have made one return new FieldMetadataBuilder(candidate); } // Candidate not found, so let's create one FieldMetadataBuilder fieldBuilder = new FieldMetadataBuilder(getId(), Modifier.PRIVATE, new ArrayList<AnnotationMetadataBuilder>(), fieldName, listType); CommentStructure comment = new CommentStructure(); comment .addComment(new JavadocComment("List of created entities."), CommentLocation.BEGINNING); fieldBuilder.setCommentStructure(comment); return fieldBuilder; } } /** * Creates an EntityFactory field related to this entity. * * @return {@link FieldMetadataBuilder} for building field into ITD. */ private FieldMetadataBuilder getEntityFactoryField() { // Create field FieldMetadataBuilder entityFactoryField = new FieldMetadataBuilder(getId(), Modifier.PRIVATE, new ArrayList<AnnotationMetadataBuilder>(), new JavaSymbolName(FACTORY_VAR), this.entityFactoryMetadata.getGovernorType()); entityFactoryField.setFieldInitializer(String.format("new %s()", getNameOfJavaType(this.entityFactoryMetadata.getGovernorType()))); CommentStructure comment = new CommentStructure(); comment.addComment(new JavadocComment("Factory to create entity instances."), CommentLocation.BEGINNING); entityFactoryField.setCommentStructure(comment); return entityFactoryField; } /** * Creates EntityManager field. * * @return {@link FieldMetadataBuilder} for building field into ITD. */ private FieldMetadataBuilder getEntityManagerField() { // Create field FieldMetadataBuilder entityManagerField = new FieldMetadataBuilder(getId(), Modifier.PRIVATE, new ArrayList<AnnotationMetadataBuilder>(), new JavaSymbolName(ENTITY_MANAGER_VAR), JpaJavaType.ENTITY_MANAGER); CommentStructure comment = new CommentStructure(); comment.addComment(new JavadocComment("EntityManager to persist the entities."), CommentLocation.BEGINNING); entityManagerField.setCommentStructure(comment); return entityManagerField; } /** * Returns the DoD type's "void init()" method (existing or generated) * * @param persistMethod * (required) * @return never `null` */ private MethodMetadataBuilder getInitMethod(final int quantity) { // Method definition to find or build final JavaSymbolName methodName = new JavaSymbolName("init"); final JavaType[] parameterTypes = {}; final List<JavaSymbolName> parameterNames = Collections.<JavaSymbolName>emptyList(); final JavaType returnType = JavaType.VOID_PRIMITIVE; // Locate user-defined method final MethodMetadata userMethod = getGovernorMethod(methodName, parameterTypes); if (userMethod != null) { Validate.isTrue(userMethod.getReturnType().equals(returnType), "Method '%s' on '%s' must return '%s'", methodName, destination, returnType.getNameIncludingTypeParameters()); return new MethodMetadataBuilder(userMethod); } // Create the method body final InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder(); bodyBuilder.appendFormalLine("int from = 0;"); bodyBuilder.appendFormalLine("int to = " + quantity + ";"); // CriteriaBuilder cb = entityManager.getCriteriaBuilder(); bodyBuilder.newLine(); bodyBuilder.appendFormalLine("%s cb = %s().getCriteriaBuilder();", getNameOfJavaType(JpaJavaType.CRITERIA_BUILDER), getAccessorMethod(getEntityManagerField().build()).getMethodName()); // CriteriaQuery<Entity> cq = cb.createQuery(Entity.class); bodyBuilder.appendFormalLine("%1$s<%2$s> cq = cb.createQuery(%2$s.class);", getNameOfJavaType(JpaJavaType.CRITERIA_QUERY), getNameOfJavaType(this.entity)); // Root<Entity> rootEntry = cq.from(Entity.class); bodyBuilder.appendFormalLine("%1$s<%2$s> rootEntry = cq.from(%2$s.class);", getNameOfJavaType(JpaJavaType.ROOT), getNameOfJavaType(this.entity)); // CriteriaQuery<Owner> all = cq.select(rootEntry); bodyBuilder.appendFormalLine("%s<%s> all = cq.select(rootEntry);", getNameOfJavaType(JpaJavaType.CRITERIA_QUERY), getNameOfJavaType(this.entity)); // TypedQuery<Owner> allQuery = bodyBuilder.appendFormalLine("%s<%s> allQuery = ", getNameOfJavaType(JpaJavaType.TYPED_QUERY), getNameOfJavaType(this.entity)); // entityManager.createQuery(all).setFirstResult(from).setMaxResults(to); bodyBuilder.indent(); bodyBuilder.appendFormalLine("%s().createQuery(all).setFirstResult(from).setMaxResults(to);", getAccessorMethod(getEntityManagerField().build()).getMethodName()); // setData(allQuery.getResultList()); bodyBuilder.indentRemove(); bodyBuilder.appendFormalLine("%s(allQuery.getResultList());", getMutatorMethod(getDataField().build()).getMethodName()); // if (getData() == null) { bodyBuilder.appendFormalLine("if (%s() == null) {", getAccessorMethod(getDataField().build()) .getMethodName()); // throw new IllegalStateException( bodyBuilder.indent(); bodyBuilder.appendFormalLine("throw new IllegalStateException("); // "Find entries implementation for 'Owner' illegally returned null"); bodyBuilder.indent(); bodyBuilder.appendFormalLine( "\"Find entries implementation for '%s' illegally returned null\");", getNameOfJavaType(this.entity)); // } bodyBuilder.indentRemove(); bodyBuilder.indentRemove(); bodyBuilder.appendFormalLine("}"); // if (!data.isEmpty()) { bodyBuilder.appendFormalLine("if (!%s().isEmpty()) {", getAccessorMethod(getDataField().build()).getMethodName()); // return; bodyBuilder.indent(); bodyBuilder.appendFormalLine("return;"); // } bodyBuilder.indentRemove(); bodyBuilder.appendFormalLine("}"); // setData(new ArrayList<Entity>()); bodyBuilder.newLine(); bodyBuilder .appendFormalLine("%s(new %s<%s>());", getMutatorMethod(getDataField().build()) .getMethodName(), getNameOfJavaType(JdkJavaType.ARRAY_LIST), getNameOfJavaType(this.entity)); // for (int i = from; i < to; i++) { bodyBuilder.appendFormalLine("for (int i = from; i < to; i++) {"); bodyBuilder.indent(); // Entity obj = factory.create(i); bodyBuilder.appendFormalLine("%s %s = %s().%s(i);", getNameOfJavaType(this.entity), OBJ_VAR, getAccessorMethod(getEntityFactoryField().build()).getMethodName(), this.entityFactoryMetadata.getCreateFactoryMethodName()); // try { bodyBuilder.appendFormalLine("try {"); bodyBuilder.indent(); // entityManager.persist(obj); bodyBuilder.appendFormalLine("%s().persist(%s);", getAccessorMethod(getEntityManagerField().build()).getMethodName(), OBJ_VAR); // } catch (final ConstraintViolationException e) { bodyBuilder.indentRemove(); bodyBuilder.appendFormalLine("} catch (final %s e) {", getNameOfJavaType(Jsr303JavaType.CONSTRAINT_VIOLATION_EXCEPTION)); bodyBuilder.indent(); // final StringBuilder msg = new StringBuilder(); bodyBuilder.appendFormalLine("final StringBuilder msg = new StringBuilder();"); // for (Iterator<ConstraintViolation<?>> iter = e.getConstraintViolations().iterator(); iter bodyBuilder.appendFormalLine( "for (%s<%s<?>> iter = e.getConstraintViolations().iterator(); iter", getNameOfJavaType(JdkJavaType.ITERATOR), getNameOfJavaType(Jsr303JavaType.CONSTRAINT_VIOLATION)); // .hasNext();) { bodyBuilder.indent(); bodyBuilder.appendFormalLine(" .hasNext();) {"); // final ConstraintViolation<?> cv = iter.next(); bodyBuilder.appendFormalLine("final %s<?> cv = iter.next();", getNameOfJavaType(Jsr303JavaType.CONSTRAINT_VIOLATION)); // msg.append("[").append(cv.getRootBean().getClass().getName()).append(".") bodyBuilder .appendFormalLine("msg.append(\"[\").append(cv.getRootBean().getClass().getName()).append(\".\")"); // .append(cv.getPropertyPath()).append(": ").append(cv.getMessage()) bodyBuilder .appendFormalLine(".append(cv.getPropertyPath()).append(\": \").append(cv.getMessage())"); // .append(" (invalid value = ").append(cv.getInvalidValue()).append(")").append("]"); bodyBuilder .appendFormalLine(".append(\" (invalid value = \").append(cv.getInvalidValue()).append(\")\").append(\"]\");"); // } bodyBuilder.indentRemove(); bodyBuilder.appendFormalLine("}"); // throw new IllegalStateException(msg.toString(), e); bodyBuilder.appendFormalLine("throw new IllegalStateException(msg.toString(), e);"); // } bodyBuilder.indentRemove(); bodyBuilder.appendFormalLine("}"); // entityManager.flush(); bodyBuilder.appendFormalLine("%s().%s();", getAccessorMethod(getEntityManagerField().build()) .getMethodName(), FLUSH_METHOD_NAME); // data.add(obj); bodyBuilder.appendFormalLine("%s().add(%s);", getAccessorMethod(getDataField().build()) .getMethodName(), OBJ_VAR); // } bodyBuilder.indentRemove(); bodyBuilder.appendFormalLine("}"); // Create the method MethodMetadataBuilder methodBuilder = new MethodMetadataBuilder(getId(), Modifier.PUBLIC, methodName, returnType, AnnotatedJavaType.convertFromJavaTypes(parameterTypes), parameterNames, bodyBuilder); CommentStructure comment = new CommentStructure(); JavadocComment javadocComment = new JavadocComment("Creates the initial list of generated entities."); comment.addComment(javadocComment, CommentLocation.BEGINNING); methodBuilder.setCommentStructure(comment); return methodBuilder; } private FieldMetadataBuilder getRndField() { int index = -1; while (true) { // Compute the required field name index++; final JavaSymbolName fieldName = new JavaSymbolName("rnd" + StringUtils.repeat("_", index)); this.rndFieldName = fieldName; final FieldMetadata candidate = governorTypeDetails.getField(fieldName); if (candidate != null) { // Verify if candidate is suitable if (!Modifier.isPrivate(candidate.getModifier())) { // Candidate is not private, so we might run into naming // clashes if someone subclasses this (therefore go onto the // next possible name) continue; } if (!candidate.getFieldType().equals(RANDOM)) { // Candidate isn't a java.util.Random, so it isn't suitable continue; } // If we got this far, we found a valid candidate // We don't check if there is a corresponding initializer, but // we assume the user knows what they're doing and have made one return new FieldMetadataBuilder(candidate); } // Candidate not found, so let's create one builder.getImportRegistrationResolver().addImports(RANDOM, SECURE_RANDOM); final FieldMetadataBuilder fieldBuilder = new FieldMetadataBuilder(getId()); fieldBuilder.setModifier(Modifier.PRIVATE); fieldBuilder.setFieldName(fieldName); fieldBuilder.setFieldType(RANDOM); fieldBuilder.setFieldInitializer("new SecureRandom()"); CommentStructure comment = new CommentStructure(); comment.addComment(new JavadocComment("Random generator for the entities index."), CommentLocation.BEGINNING); fieldBuilder.setCommentStructure(comment); return fieldBuilder; } } /** * Creates size field. * * @return {@link FieldMetadataBuilder} for building field into ITD. */ private FieldMetadata getSizeField() { // Create field FieldMetadataBuilder sizeField = new FieldMetadataBuilder(getId(), Modifier.PRIVATE, new ArrayList<AnnotationMetadataBuilder>(), new JavaSymbolName(SIZE_VAR), JavaType.INT_PRIMITIVE); CommentStructure comment = new CommentStructure(); comment.addComment(new JavadocComment("Number of elements to create and persist."), CommentLocation.BEGINNING); sizeField.setCommentStructure(comment); return sizeField.build(); } private MethodMetadata getSpecificEntityMethod() { // Method definition to find or build final JavaSymbolName methodName = new JavaSymbolName(JpaEntityFactoryMetadata.SPECIFIC_METHOD_PREFIX + this.entity.getSimpleTypeName()); final JavaType parameterType = JavaType.INT_PRIMITIVE; final List<JavaSymbolName> parameterNames = Arrays.asList(INDEX_SYMBOL); // Locate user-defined method final MethodMetadata userMethod = getGovernorMethod(methodName, parameterType); if (userMethod != null) { Validate.isTrue(userMethod.getReturnType().equals(this.entity), "Method '%s on '%s' must return '%s'", methodName, this.destination, this.entity.getSimpleTypeName()); this.specificEntityMethod = userMethod; return userMethod; } // Create method final InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder(); bodyBuilder.appendFormalLine("init();"); bodyBuilder.appendFormalLine("if (" + INDEX_VAR + " < 0) {"); bodyBuilder.indent(); bodyBuilder.appendFormalLine(INDEX_VAR + " = 0;"); bodyBuilder.indentRemove(); bodyBuilder.appendFormalLine("}"); bodyBuilder.appendFormalLine("if (" + INDEX_VAR + " > (" + getAccessorMethod(getDataField().build()).getMethodName() + "().size() - 1)) {"); bodyBuilder.indent(); bodyBuilder.appendFormalLine(INDEX_VAR + " = " + getAccessorMethod(getDataField().build()).getMethodName() + "().size() - 1;"); bodyBuilder.indentRemove(); bodyBuilder.appendFormalLine("}"); bodyBuilder.appendFormalLine("return %s().get(%s);", getAccessorMethod(getDataField().build()) .getMethodName(), INDEX_VAR); final MethodMetadataBuilder methodBuilder = new MethodMetadataBuilder(getId(), Modifier.PUBLIC, methodName, this.entity, AnnotatedJavaType.convertFromJavaTypes(parameterType), parameterNames, bodyBuilder); CommentStructure comment = new CommentStructure(); List<String> paramsInfo = new ArrayList<String>(); paramsInfo.add(String.format("%s the position of the {@link %s} to return", INDEX_VAR, this.entity.getSimpleTypeName())); JavadocComment javadocComment = new JavadocComment(String.format( "Returns a generated and persisted {@link %s} in a given index.", this.entity.getSimpleTypeName()), paramsInfo, String.format( "%1$s the specific {@link %1$s}", this.entity.getSimpleTypeName()), null); comment.addComment(javadocComment, CommentLocation.BEGINNING); methodBuilder.setCommentStructure(comment); this.specificEntityMethod = methodBuilder.build(); return this.specificEntityMethod; } /** * @return the "getRandomEntity():Entity" method (never returns null) */ private MethodMetadata getRandomPersistentEntityMethod() { // Method definition to find or build final JavaSymbolName methodName = new JavaSymbolName("getRandom" + this.entity.getSimpleTypeName()); // Locate user-defined method final MethodMetadata userMethod = getGovernorMethod(methodName); if (userMethod != null) { Validate.isTrue(userMethod.getReturnType().equals(this.entity), "Method '%s' on '%s' must return '%s'", methodName, this.destination, this.entity.getSimpleTypeName()); this.randomPersistentEntityMethod = userMethod; return userMethod; } // Create method final InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder(); // init(); bodyBuilder.appendFormalLine("init();"); // return data.get(rnd.nextInt(data.size())); bodyBuilder.appendFormalLine("return %1$s().get(%2$s().nextInt(%1$s().size()));", getAccessorMethod(getDataField().build()).getMethodName(), getAccessorMethod(getRndField().build()).getMethodName()); final MethodMetadataBuilder methodBuilder = new MethodMetadataBuilder(getId(), Modifier.PUBLIC, methodName, this.entity, bodyBuilder); CommentStructure comment = new CommentStructure(); JavadocComment javadocComment = new JavadocComment(String.format( "Returns a generated and persisted {@link %s} in a random index.", this.entity.getSimpleTypeName()), null, String.format("%1$s a random {@link %1$s}", this.entity.getSimpleTypeName()), null); comment.addComment(javadocComment, CommentLocation.BEGINNING); methodBuilder.setCommentStructure(comment); this.randomPersistentEntityMethod = methodBuilder.build(); return this.randomPersistentEntityMethod; } private MethodMetadata getNewRandomTransientEntityMethod() { // Method definition to find or build final JavaSymbolName methodName = new JavaSymbolName("getNewRandomTransient" + this.entity.getSimpleTypeName()); // Locate user-defined method final MethodMetadata userMethod = getGovernorMethod(methodName); if (userMethod != null) { Validate.isTrue(userMethod.getReturnType().equals(entity), "Method '%s' on '%s' must return '%s'", methodName, this.destination, this.entity.getSimpleTypeName()); this.newTransientEntityMethod = userMethod; return userMethod; } // Create method final InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder(); // int randomIndex = getSize() + rnd.nextInt(Integer.MAX_VALUE - getSize()); bodyBuilder.appendFormalLine( "int randomIndex = %1$s() + %2$s().nextInt(Integer.MAX_VALUE - %1$s());", this.sizeAccesorName, getAccessorMethod(getRndField().build()).getMethodName()); // return factory.create(randomIndex); bodyBuilder.appendFormalLine("return %s().%s(randomIndex);", getAccessorMethod(getEntityFactoryField().build()).getMethodName(), this.entityFactoryMetadata.getCreateFactoryMethodName()); final MethodMetadataBuilder methodBuilder = new MethodMetadataBuilder(getId(), Modifier.PUBLIC, methodName, this.entity, bodyBuilder); CommentStructure comment = new CommentStructure(); JavadocComment javadocComment = new JavadocComment(String.format( "Creates a new transient %s in a random index out of " + "the initial list of the created entities,".concat(IOUtils.LINE_SEPARATOR) .concat("with an index greater than {@link %s#getSize()} - 1."), this.entity .getSimpleTypeName(), this.governorPhysicalTypeMetadata.getType() .getSimpleTypeName()), null, String.format( "%1$s the generated transient {@link %1$s}", this.entity.getSimpleTypeName()), null); comment.addComment(javadocComment, CommentLocation.BEGINNING); methodBuilder.setCommentStructure(comment); this.newTransientEntityMethod = methodBuilder.build(); return this.newTransientEntityMethod; } public JavaType getEntityType() { return this.entity; } /** * @return the "getNewTransientEntity(int index):Entity" method (never * returns null) */ public MethodMetadata getNewTransientEntityMethod() { return this.newTransientEntityMethod; } /** * @return the "getRandomEntity():Entity" method (never returns null) */ public MethodMetadata getRandomPersistentEntityMethodGetter() { return this.randomPersistentEntityMethod; } public boolean hasEmbeddedIdentifier() { return this.embeddedIdHolder != null; } /** * @return the "getSpecificEntity(int):Entity" method (never returns null) */ public MethodMetadata getSpecificPersistentEntityMethodGetter() { return this.specificEntityMethod; } @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("governor", governorPhysicalTypeMetadata.getId()); builder.append("itdTypeDetails", itdTypeDetails); return builder.toString(); } }