package org.springframework.roo.addon.web.mvc.controller.json; import static java.lang.reflect.Modifier.PUBLIC; import static org.springframework.roo.classpath.customdata.CustomDataKeys.FIND_ALL_METHOD; import static org.springframework.roo.classpath.customdata.CustomDataKeys.FIND_METHOD; import static org.springframework.roo.classpath.customdata.CustomDataKeys.MERGE_METHOD; import static org.springframework.roo.classpath.customdata.CustomDataKeys.PERSIST_METHOD; import static org.springframework.roo.classpath.customdata.CustomDataKeys.REMOVE_METHOD; import static org.springframework.roo.model.JdkJavaType.CALENDAR; import static org.springframework.roo.model.JdkJavaType.DATE; import static org.springframework.roo.model.SpringJavaType.DATE_TIME_FORMAT; import static org.springframework.roo.model.SpringJavaType.HTTP_HEADERS; import static org.springframework.roo.model.SpringJavaType.HTTP_STATUS; import static org.springframework.roo.model.SpringJavaType.PATH_VARIABLE; import static org.springframework.roo.model.SpringJavaType.REQUEST_BODY; import static org.springframework.roo.model.SpringJavaType.REQUEST_MAPPING; import static org.springframework.roo.model.SpringJavaType.REQUEST_METHOD; import static org.springframework.roo.model.SpringJavaType.REQUEST_PARAM; import static org.springframework.roo.model.SpringJavaType.RESPONSE_BODY; import static org.springframework.roo.model.SpringJavaType.RESPONSE_ENTITY; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.builder.ToStringBuilder; import org.springframework.roo.addon.json.JsonMetadata; import org.springframework.roo.addon.web.mvc.controller.details.FinderMetadataDetails; import org.springframework.roo.addon.web.mvc.controller.scaffold.RooWebScaffold; import org.springframework.roo.classpath.PhysicalTypeIdentifierNamingUtils; import org.springframework.roo.classpath.PhysicalTypeMetadata; import org.springframework.roo.classpath.customdata.tagkeys.MethodMetadataCustomDataKey; import org.springframework.roo.classpath.details.FieldMetadata; import org.springframework.roo.classpath.details.MemberFindingUtils; import org.springframework.roo.classpath.details.MethodMetadataBuilder; import org.springframework.roo.classpath.details.annotations.AnnotatedJavaType; import org.springframework.roo.classpath.details.annotations.AnnotationAttributeValue; import org.springframework.roo.classpath.details.annotations.AnnotationMetadata; import org.springframework.roo.classpath.details.annotations.AnnotationMetadataBuilder; import org.springframework.roo.classpath.details.annotations.BooleanAttributeValue; import org.springframework.roo.classpath.details.annotations.EnumAttributeValue; import org.springframework.roo.classpath.details.annotations.StringAttributeValue; import org.springframework.roo.classpath.itd.AbstractItdTypeDetailsProvidingMetadataItem; import org.springframework.roo.classpath.itd.InvocableMemberBodyBuilder; import org.springframework.roo.classpath.layers.MemberTypeAdditions; 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 Json functionality provided through {@link RooWebScaffold}. * * @author Stefan Schmidt * @since 1.1.3 */ public class WebJsonMetadata extends AbstractItdTypeDetailsProvidingMetadataItem { private static final String CONTENT_TYPE = "application/json"; private static final String PROVIDES_TYPE_STRING = WebJsonMetadata.class .getName(); private static final String PROVIDES_TYPE = MetadataIdentificationUtils .create(PROVIDES_TYPE_STRING); private static final JavaType RESPONSE_ENTITY_STRING = new JavaType( RESPONSE_ENTITY.getFullyQualifiedTypeName(), 0, DataType.TYPE, null, Arrays.asList(JavaType.STRING)); 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 WebJsonAnnotationValues annotationValues; private boolean introduceLayerComponents; private JavaType jsonEnabledType; private String jsonEnabledTypeShortName; private JsonMetadata jsonMetadata; private String jsonBeanName; /** * Constructor * * @param identifier * @param aspectName * @param governorPhysicalTypeMetadata * @param annotationValues * @param persistenceAdditions * @param identifierField * @param plural * @param finderDetails (required) * @param jsonMetadata * @param introduceLayerComponents whether to introduce any required layer * components (services, repositories, etc.) */ public WebJsonMetadata( final String identifier, final JavaType aspectName, final PhysicalTypeMetadata governorPhysicalTypeMetadata, final WebJsonAnnotationValues annotationValues, final Map<MethodMetadataCustomDataKey, MemberTypeAdditions> persistenceAdditions, final FieldMetadata identifierField, final String plural, final Set<FinderMetadataDetails> finderDetails, final JsonMetadata jsonMetadata, final boolean introduceLayerComponents) { super(identifier, aspectName, governorPhysicalTypeMetadata); Validate.isTrue(isValid(identifier), "Metadata identification string '" + identifier + "' is invalid"); Validate.notNull(annotationValues, "Annotation values required"); Validate.notNull(persistenceAdditions, "Persistence additions required"); Validate.notNull(finderDetails, "Set of dynamic finder methods cannot be null"); Validate.notNull(jsonMetadata, "Json metadata required"); if (!isValid()) { return; } this.annotationValues = annotationValues; jsonEnabledType = annotationValues.getJsonObject(); jsonEnabledTypeShortName = getShortName(jsonEnabledType); jsonBeanName = JavaSymbolName.getReservedWordSafeName(jsonEnabledType) .getSymbolName(); this.introduceLayerComponents = introduceLayerComponents; this.jsonMetadata = jsonMetadata; final MemberTypeAdditions findMethod = persistenceAdditions .get(FIND_METHOD); builder.addMethod(getShowJsonMethod(identifierField, findMethod)); final MemberTypeAdditions findAllMethod = persistenceAdditions .get(FIND_ALL_METHOD); builder.addMethod(getListJsonMethod(findAllMethod)); final MemberTypeAdditions persistMethod = persistenceAdditions .get(PERSIST_METHOD); builder.addMethod(getCreateFromJsonMethod(persistMethod)); builder.addMethod(getCreateFromJsonArrayMethod(persistMethod)); final MemberTypeAdditions mergeMethod = persistenceAdditions .get(MERGE_METHOD); builder.addMethod(getUpdateFromJsonMethod(mergeMethod)); builder.addMethod(getUpdateFromJsonArrayMethod(mergeMethod)); final MemberTypeAdditions removeMethod = persistenceAdditions .get(REMOVE_METHOD); builder.addMethod(getDeleteFromJsonMethod(removeMethod, identifierField, findMethod)); if (annotationValues.isExposeFinders()) { for (final FinderMetadataDetails finder : finderDetails) { builder.addMethod(getJsonFindMethod(finder, plural)); } } itdTypeDetails = builder.build(); } private MethodMetadataBuilder getCreateFromJsonArrayMethod( final MemberTypeAdditions persistMethod) { if (StringUtils .isBlank(annotationValues.getCreateFromJsonArrayMethod()) || persistMethod == null) { return null; } final JavaSymbolName methodName = new JavaSymbolName( annotationValues.getCreateFromJsonArrayMethod()); if (governorHasMethodWithSameName(methodName)) { return null; } final JavaSymbolName fromJsonArrayMethodName = jsonMetadata .getFromJsonArrayMethodName(); final AnnotationMetadataBuilder requestBodyAnnotation = new AnnotationMetadataBuilder( REQUEST_BODY); final List<AnnotatedJavaType> parameterTypes = Arrays .asList(new AnnotatedJavaType(JavaType.STRING, requestBodyAnnotation.build())); final List<JavaSymbolName> parameterNames = Arrays .asList(new JavaSymbolName("json")); final List<AnnotationAttributeValue<?>> requestMappingAttributes = new ArrayList<AnnotationAttributeValue<?>>(); requestMappingAttributes.add(new StringAttributeValue( new JavaSymbolName("value"), "/jsonArray")); requestMappingAttributes.add(new EnumAttributeValue(new JavaSymbolName( "method"), new EnumDetails(REQUEST_METHOD, new JavaSymbolName( "POST")))); requestMappingAttributes.add(new StringAttributeValue( new JavaSymbolName("headers"), "Accept=application/json")); final AnnotationMetadataBuilder requestMapping = new AnnotationMetadataBuilder( REQUEST_MAPPING, requestMappingAttributes); final List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>(); annotations.add(requestMapping); final List<JavaType> params = new ArrayList<JavaType>(); params.add(jsonEnabledType); final InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder(); bodyBuilder.appendFormalLine("for (" + jsonEnabledTypeShortName + " " + jsonBeanName + ": " + jsonEnabledTypeShortName + "." + fromJsonArrayMethodName.getSymbolName() + "(json)) {"); bodyBuilder.indent(); bodyBuilder.appendFormalLine(persistMethod.getMethodCall() + ";"); bodyBuilder.indentRemove(); bodyBuilder.appendFormalLine("}"); final String httpHeadersShortName = getShortName(HTTP_HEADERS); bodyBuilder.appendFormalLine(httpHeadersShortName + " headers = new " + httpHeadersShortName + "();"); bodyBuilder.appendFormalLine("headers.add(\"Content-Type\", \"" + CONTENT_TYPE + "\");"); bodyBuilder .appendFormalLine("return new ResponseEntity<String>(headers, " + getShortName(HTTP_STATUS) + ".CREATED);"); if (introduceLayerComponents) { persistMethod.copyAdditionsTo(builder, governorTypeDetails); } final MethodMetadataBuilder methodBuilder = new MethodMetadataBuilder( getId(), PUBLIC, methodName, RESPONSE_ENTITY_STRING, parameterTypes, parameterNames, bodyBuilder); methodBuilder.setAnnotations(annotations); return methodBuilder; } private MethodMetadataBuilder getCreateFromJsonMethod( final MemberTypeAdditions persistMethod) { if (StringUtils.isBlank(annotationValues.getCreateFromJsonMethod()) || persistMethod == null) { return null; } final JavaSymbolName methodName = new JavaSymbolName( annotationValues.getCreateFromJsonMethod()); if (governorHasMethodWithSameName(methodName)) { return null; } final JavaSymbolName fromJsonMethodName = jsonMetadata .getFromJsonMethodName(); final AnnotationMetadataBuilder requestBodyAnnotation = new AnnotationMetadataBuilder( REQUEST_BODY); final List<AnnotatedJavaType> parameterTypes = Arrays .asList(new AnnotatedJavaType(JavaType.STRING, requestBodyAnnotation.build())); final List<JavaSymbolName> parameterNames = Arrays .asList(new JavaSymbolName("json")); final List<AnnotationAttributeValue<?>> requestMappingAttributes = new ArrayList<AnnotationAttributeValue<?>>(); requestMappingAttributes.add(new EnumAttributeValue(new JavaSymbolName( "method"), new EnumDetails(REQUEST_METHOD, new JavaSymbolName( "POST")))); requestMappingAttributes.add(new StringAttributeValue( new JavaSymbolName("headers"), "Accept=application/json")); final AnnotationMetadataBuilder requestMapping = new AnnotationMetadataBuilder( REQUEST_MAPPING, requestMappingAttributes); final List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>(); annotations.add(requestMapping); final InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder(); bodyBuilder.appendFormalLine(jsonEnabledTypeShortName + " " + jsonBeanName + " = " + jsonEnabledTypeShortName + "." + fromJsonMethodName.getSymbolName() + "(json);"); bodyBuilder.appendFormalLine(persistMethod.getMethodCall() + ";"); final String httpHeadersShortName = getShortName(HTTP_HEADERS); bodyBuilder.appendFormalLine(httpHeadersShortName + " headers = new " + httpHeadersShortName + "();"); bodyBuilder.appendFormalLine("headers.add(\"Content-Type\", \"" + CONTENT_TYPE + "\");"); bodyBuilder .appendFormalLine("return new ResponseEntity<String>(headers, " + getShortName(HTTP_STATUS) + ".CREATED);"); if (introduceLayerComponents) { persistMethod.copyAdditionsTo(builder, governorTypeDetails); } final MethodMetadataBuilder methodBuilder = new MethodMetadataBuilder( getId(), PUBLIC, methodName, RESPONSE_ENTITY_STRING, parameterTypes, parameterNames, bodyBuilder); methodBuilder.setAnnotations(annotations); return methodBuilder; } private MethodMetadataBuilder getDeleteFromJsonMethod( final MemberTypeAdditions removeMethod, final FieldMetadata identifierField, final MemberTypeAdditions findMethod) { if (StringUtils.isBlank(annotationValues.getDeleteFromJsonMethod()) || removeMethod == null || identifierField == null || findMethod == null) { return null; } final JavaSymbolName methodName = new JavaSymbolName( annotationValues.getDeleteFromJsonMethod()); if (governorHasMethodWithSameName(methodName)) { return null; } final List<AnnotationAttributeValue<?>> attributes = new ArrayList<AnnotationAttributeValue<?>>(); attributes.add(new StringAttributeValue(new JavaSymbolName("value"), identifierField.getFieldName().getSymbolName())); final AnnotationMetadataBuilder pathVariableAnnotation = new AnnotationMetadataBuilder( PATH_VARIABLE, attributes); final List<AnnotatedJavaType> parameterTypes = Arrays .asList(new AnnotatedJavaType(identifierField.getFieldType(), pathVariableAnnotation.build())); final List<JavaSymbolName> parameterNames = Arrays .asList(identifierField.getFieldName()); final List<AnnotationAttributeValue<?>> requestMappingAttributes = new ArrayList<AnnotationAttributeValue<?>>(); requestMappingAttributes .add(new StringAttributeValue(new JavaSymbolName("value"), "/{" + identifierField.getFieldName().getSymbolName() + "}")); requestMappingAttributes.add(new EnumAttributeValue(new JavaSymbolName( "method"), new EnumDetails(REQUEST_METHOD, new JavaSymbolName( "DELETE")))); requestMappingAttributes.add(new StringAttributeValue( new JavaSymbolName("headers"), "Accept=application/json")); final AnnotationMetadataBuilder requestMapping = new AnnotationMetadataBuilder( REQUEST_MAPPING, requestMappingAttributes); final List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>(); annotations.add(requestMapping); final String httpHeadersShortName = getShortName(HTTP_HEADERS); final InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder(); bodyBuilder.appendFormalLine(jsonEnabledTypeShortName + " " + jsonBeanName + " = " + findMethod.getMethodCall() + ";"); bodyBuilder.appendFormalLine(httpHeadersShortName + " headers = new " + httpHeadersShortName + "();"); bodyBuilder.appendFormalLine("headers.add(\"Content-Type\", \"" + CONTENT_TYPE + "\");"); bodyBuilder.appendFormalLine("if (" + jsonBeanName + " == null) {"); bodyBuilder.indent(); bodyBuilder.appendFormalLine("return new " + getShortName(RESPONSE_ENTITY) + "<String>(headers, " + getShortName(HTTP_STATUS) + ".NOT_FOUND);"); bodyBuilder.indentRemove(); bodyBuilder.appendFormalLine("}"); bodyBuilder.appendFormalLine(removeMethod.getMethodCall() + ";"); bodyBuilder .appendFormalLine("return new ResponseEntity<String>(headers, " + getShortName(HTTP_STATUS) + ".OK);"); if (introduceLayerComponents) { removeMethod.copyAdditionsTo(builder, governorTypeDetails); findMethod.copyAdditionsTo(builder, governorTypeDetails); } final MethodMetadataBuilder methodBuilder = new MethodMetadataBuilder( getId(), PUBLIC, methodName, RESPONSE_ENTITY_STRING, parameterTypes, parameterNames, bodyBuilder); methodBuilder.setAnnotations(annotations); return methodBuilder; } private MethodMetadataBuilder getJsonFindMethod( final FinderMetadataDetails finderDetails, final String plural) { if (finderDetails == null || jsonMetadata.getToJsonArrayMethodName() == null) { return null; } final JavaSymbolName finderMethodName = new JavaSymbolName("json" + StringUtils.capitalize(finderDetails .getFinderMethodMetadata().getMethodName() .getSymbolName())); if (governorHasMethodWithSameName(finderMethodName)) { return null; } final List<AnnotatedJavaType> parameterTypes = new ArrayList<AnnotatedJavaType>(); final List<JavaSymbolName> parameterNames = new ArrayList<JavaSymbolName>(); final StringBuilder methodParams = new StringBuilder(); for (final FieldMetadata field : finderDetails .getFinderMethodParamFields()) { final JavaSymbolName fieldName = field.getFieldName(); final List<AnnotationMetadata> annotations = new ArrayList<AnnotationMetadata>(); final List<AnnotationAttributeValue<?>> attributes = new ArrayList<AnnotationAttributeValue<?>>(); attributes.add(new StringAttributeValue( new JavaSymbolName("value"), StringUtils .uncapitalize(fieldName.getSymbolName()))); if (field.getFieldType().equals(JavaType.BOOLEAN_PRIMITIVE) || field.getFieldType().equals(JavaType.BOOLEAN_OBJECT)) { attributes.add(new BooleanAttributeValue(new JavaSymbolName( "required"), false)); } final AnnotationMetadataBuilder requestParamAnnotation = new AnnotationMetadataBuilder( REQUEST_PARAM, attributes); annotations.add(requestParamAnnotation.build()); if (field.getFieldType().equals(DATE) || field.getFieldType().equals(CALENDAR)) { final AnnotationMetadata annotation = MemberFindingUtils .getAnnotationOfType(field.getAnnotations(), DATE_TIME_FORMAT); if (annotation != null) { annotations.add(annotation); } } parameterNames.add(fieldName); parameterTypes.add(new AnnotatedJavaType(field.getFieldType(), annotations)); if (field.getFieldType().equals(JavaType.BOOLEAN_OBJECT)) { methodParams.append(field.getFieldName() + " == null ? Boolean.FALSE : " + field.getFieldName() + ", "); } else { methodParams.append(field.getFieldName() + ", "); } } if (methodParams.length() > 0) { methodParams.delete(methodParams.length() - 2, methodParams.length()); } final List<JavaSymbolName> newParamNames = new ArrayList<JavaSymbolName>(); newParamNames.addAll(parameterNames); final List<AnnotationAttributeValue<?>> requestMappingAttributes = new ArrayList<AnnotationAttributeValue<?>>(); requestMappingAttributes.add(new StringAttributeValue( new JavaSymbolName("params"), "find=" + finderDetails.getFinderMethodMetadata() .getMethodName().getSymbolName() .replaceFirst("find" + plural, ""))); requestMappingAttributes.add(new StringAttributeValue( new JavaSymbolName("headers"), "Accept=application/json")); final AnnotationMetadataBuilder requestMapping = new AnnotationMetadataBuilder( REQUEST_MAPPING, requestMappingAttributes); final List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>(); annotations.add(requestMapping); annotations.add(new AnnotationMetadataBuilder(RESPONSE_BODY)); final String httpHeadersShortName = getShortName(HTTP_HEADERS); final String responseEntityShortName = getShortName(RESPONSE_ENTITY); final String httpStatusShortName = getShortName(HTTP_STATUS); final InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder(); bodyBuilder.appendFormalLine(httpHeadersShortName + " headers = new " + httpHeadersShortName + "();"); bodyBuilder.appendFormalLine("headers.add(\"Content-Type\", \"" + CONTENT_TYPE + "; charset=utf-8\");"); bodyBuilder.appendFormalLine("return new " + responseEntityShortName + "<String>(" + jsonEnabledTypeShortName + "." + jsonMetadata.getToJsonArrayMethodName().getSymbolName() .toString() + "(" + jsonEnabledTypeShortName + "." + finderDetails.getFinderMethodMetadata().getMethodName() .getSymbolName() + "(" + methodParams.toString() + ").getResultList()), headers, " + httpStatusShortName + ".OK);"); final MethodMetadataBuilder methodBuilder = new MethodMetadataBuilder( getId(), PUBLIC, finderMethodName, RESPONSE_ENTITY_STRING, parameterTypes, newParamNames, bodyBuilder); methodBuilder.setAnnotations(annotations); return methodBuilder; } private MethodMetadataBuilder getListJsonMethod( final MemberTypeAdditions findAllMethod) { if (StringUtils.isBlank(annotationValues.getListJsonMethod()) || findAllMethod == null) { return null; } final JavaSymbolName methodName = new JavaSymbolName( annotationValues.getListJsonMethod()); if (governorHasMethodWithSameName(methodName)) { return null; } final JavaSymbolName toJsonArrayMethodName = jsonMetadata .getToJsonArrayMethodName(); final List<AnnotationAttributeValue<?>> requestMappingAttributes = new ArrayList<AnnotationAttributeValue<?>>(); requestMappingAttributes.add(new StringAttributeValue( new JavaSymbolName("headers"), "Accept=application/json")); final AnnotationMetadataBuilder requestMapping = new AnnotationMetadataBuilder( REQUEST_MAPPING, requestMappingAttributes); final List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>(); annotations.add(requestMapping); annotations.add(new AnnotationMetadataBuilder(RESPONSE_BODY)); final String httpHeadersShortName = getShortName(HTTP_HEADERS); final String responseEntityShortName = getShortName(RESPONSE_ENTITY); final String httpStatusShortName = getShortName(HTTP_STATUS); final InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder(); bodyBuilder.appendFormalLine(httpHeadersShortName + " headers = new " + httpHeadersShortName + "();"); bodyBuilder.appendFormalLine("headers.add(\"Content-Type\", \"" + CONTENT_TYPE + "; charset=utf-8\");"); final JavaType list = new JavaType(List.class.getName(), 0, DataType.TYPE, null, Arrays.asList(jsonEnabledType)); bodyBuilder.appendFormalLine(getShortName(list) + " result = " + findAllMethod.getMethodCall() + ";"); bodyBuilder.appendFormalLine("return new " + responseEntityShortName + "<String>(" + jsonEnabledTypeShortName + "." + toJsonArrayMethodName.getSymbolName() + "(result), headers, " + httpStatusShortName + ".OK);"); if (introduceLayerComponents) { findAllMethod.copyAdditionsTo(builder, governorTypeDetails); } final MethodMetadataBuilder methodBuilder = new MethodMetadataBuilder( getId(), PUBLIC, methodName, RESPONSE_ENTITY_STRING, bodyBuilder); methodBuilder.setAnnotations(annotations); return methodBuilder; } private String getShortName(final JavaType type) { return type.getNameIncludingTypeParameters(false, builder.getImportRegistrationResolver()); } private MethodMetadataBuilder getShowJsonMethod( final FieldMetadata identifierField, final MemberTypeAdditions findMethod) { if (StringUtils.isBlank(annotationValues.getShowJsonMethod()) || identifierField == null || findMethod == null) { return null; } final JavaSymbolName methodName = new JavaSymbolName( annotationValues.getShowJsonMethod()); if (governorHasMethodWithSameName(methodName)) { return null; } final JavaSymbolName toJsonMethodName = jsonMetadata .getToJsonMethodName(); final List<AnnotationAttributeValue<?>> attributes = new ArrayList<AnnotationAttributeValue<?>>(); attributes.add(new StringAttributeValue(new JavaSymbolName("value"), identifierField.getFieldName().getSymbolName())); final AnnotationMetadataBuilder pathVariableAnnotation = new AnnotationMetadataBuilder( PATH_VARIABLE, attributes); final List<AnnotatedJavaType> parameterTypes = Arrays .asList(new AnnotatedJavaType(identifierField.getFieldType(), pathVariableAnnotation.build())); final List<JavaSymbolName> parameterNames = Arrays .asList(new JavaSymbolName(identifierField.getFieldName() .getSymbolName())); final List<AnnotationAttributeValue<?>> requestMappingAttributes = new ArrayList<AnnotationAttributeValue<?>>(); requestMappingAttributes .add(new StringAttributeValue(new JavaSymbolName("value"), "/{" + identifierField.getFieldName().getSymbolName() + "}")); requestMappingAttributes.add(new StringAttributeValue( new JavaSymbolName("headers"), "Accept=application/json")); final AnnotationMetadataBuilder requestMapping = new AnnotationMetadataBuilder( REQUEST_MAPPING, requestMappingAttributes); final List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>(); annotations.add(requestMapping); annotations.add(new AnnotationMetadataBuilder(RESPONSE_BODY)); final String httpHeadersShortName = getShortName(HTTP_HEADERS); final String responseEntityShortName = getShortName(RESPONSE_ENTITY); final String httpStatusShortName = getShortName(HTTP_STATUS); final InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder(); bodyBuilder.appendFormalLine(jsonEnabledTypeShortName + " " + jsonBeanName + " = " + findMethod.getMethodCall() + ";"); bodyBuilder.appendFormalLine(httpHeadersShortName + " headers = new " + httpHeadersShortName + "();"); bodyBuilder.appendFormalLine("headers.add(\"Content-Type\", \"" + CONTENT_TYPE + "; charset=utf-8\");"); bodyBuilder.appendFormalLine("if (" + jsonBeanName + " == null) {"); bodyBuilder.indent(); bodyBuilder.appendFormalLine("return new " + responseEntityShortName + "<String>(headers, " + httpStatusShortName + ".NOT_FOUND);"); bodyBuilder.indentRemove(); bodyBuilder.appendFormalLine("}"); bodyBuilder.appendFormalLine("return new " + responseEntityShortName + "<String>(" + jsonBeanName + "." + toJsonMethodName.getSymbolName() + "(), headers, " + httpStatusShortName + ".OK);"); if (introduceLayerComponents) { findMethod.copyAdditionsTo(builder, governorTypeDetails); } final MethodMetadataBuilder methodBuilder = new MethodMetadataBuilder( getId(), PUBLIC, methodName, RESPONSE_ENTITY_STRING, parameterTypes, parameterNames, bodyBuilder); methodBuilder.setAnnotations(annotations); return methodBuilder; } private MethodMetadataBuilder getUpdateFromJsonArrayMethod( final MemberTypeAdditions mergeMethod) { if (StringUtils .isBlank(annotationValues.getUpdateFromJsonArrayMethod()) || mergeMethod == null) { return null; } final JavaSymbolName methodName = new JavaSymbolName( annotationValues.getUpdateFromJsonArrayMethod()); if (governorHasMethodWithSameName(methodName)) { return null; } final JavaSymbolName fromJsonArrayMethodName = jsonMetadata .getFromJsonArrayMethodName(); final AnnotationMetadataBuilder requestBodyAnnotation = new AnnotationMetadataBuilder( REQUEST_BODY); final List<AnnotatedJavaType> parameterTypes = Arrays .asList(new AnnotatedJavaType(JavaType.STRING, requestBodyAnnotation.build())); final List<JavaSymbolName> parameterNames = Arrays .asList(new JavaSymbolName("json")); final List<AnnotationAttributeValue<?>> requestMappingAttributes = new ArrayList<AnnotationAttributeValue<?>>(); requestMappingAttributes.add(new StringAttributeValue( new JavaSymbolName("value"), "/jsonArray")); requestMappingAttributes.add(new EnumAttributeValue(new JavaSymbolName( "method"), new EnumDetails(REQUEST_METHOD, new JavaSymbolName( "PUT")))); requestMappingAttributes.add(new StringAttributeValue( new JavaSymbolName("headers"), "Accept=application/json")); final AnnotationMetadataBuilder requestMapping = new AnnotationMetadataBuilder( REQUEST_MAPPING, requestMappingAttributes); final List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>(); annotations.add(requestMapping); final List<JavaType> params = new ArrayList<JavaType>(); params.add(jsonEnabledType); final String httpHeadersShortName = getShortName(HTTP_HEADERS); final InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder(); bodyBuilder.appendFormalLine(httpHeadersShortName + " headers = new " + httpHeadersShortName + "();"); bodyBuilder.appendFormalLine("headers.add(\"Content-Type\", \"" + CONTENT_TYPE + "\");"); bodyBuilder.appendFormalLine("for (" + jsonEnabledTypeShortName + " " + jsonBeanName + ": " + jsonEnabledTypeShortName + "." + fromJsonArrayMethodName.getSymbolName() + "(json)) {"); bodyBuilder.indent(); bodyBuilder.appendFormalLine("if (" + mergeMethod.getMethodCall() + " == null) {"); bodyBuilder.indent(); bodyBuilder .appendFormalLine("return new ResponseEntity<String>(headers, " + getShortName(HTTP_STATUS) + ".NOT_FOUND);"); bodyBuilder.indentRemove(); bodyBuilder.appendFormalLine("}"); bodyBuilder.indentRemove(); bodyBuilder.appendFormalLine("}"); bodyBuilder .appendFormalLine("return new ResponseEntity<String>(headers, " + getShortName(HTTP_STATUS) + ".OK);"); if (introduceLayerComponents) { mergeMethod.copyAdditionsTo(builder, governorTypeDetails); } final MethodMetadataBuilder methodBuilder = new MethodMetadataBuilder( getId(), PUBLIC, methodName, RESPONSE_ENTITY_STRING, parameterTypes, parameterNames, bodyBuilder); methodBuilder.setAnnotations(annotations); return methodBuilder; } private MethodMetadataBuilder getUpdateFromJsonMethod( final MemberTypeAdditions mergeMethod) { if (StringUtils.isBlank(annotationValues.getUpdateFromJsonMethod()) || mergeMethod == null) { return null; } final JavaSymbolName methodName = new JavaSymbolName( annotationValues.getUpdateFromJsonMethod()); if (governorHasMethodWithSameName(methodName)) { return null; } final JavaSymbolName fromJsonMethodName = jsonMetadata .getFromJsonMethodName(); final AnnotationMetadataBuilder requestBodyAnnotation = new AnnotationMetadataBuilder( REQUEST_BODY); final List<AnnotatedJavaType> parameterTypes = Arrays .asList(new AnnotatedJavaType(JavaType.STRING, requestBodyAnnotation.build())); final List<JavaSymbolName> parameterNames = Arrays .asList(new JavaSymbolName("json")); final List<AnnotationAttributeValue<?>> requestMappingAttributes = new ArrayList<AnnotationAttributeValue<?>>(); requestMappingAttributes.add(new EnumAttributeValue(new JavaSymbolName( "method"), new EnumDetails(REQUEST_METHOD, new JavaSymbolName( "PUT")))); requestMappingAttributes.add(new StringAttributeValue( new JavaSymbolName("headers"), "Accept=application/json")); final AnnotationMetadataBuilder requestMapping = new AnnotationMetadataBuilder( REQUEST_MAPPING, requestMappingAttributes); final List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>(); annotations.add(requestMapping); final String httpHeadersShortName = getShortName(HTTP_HEADERS); final InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder(); bodyBuilder.appendFormalLine(httpHeadersShortName + " headers = new " + httpHeadersShortName + "();"); bodyBuilder.appendFormalLine("headers.add(\"Content-Type\", \"" + CONTENT_TYPE + "\");"); bodyBuilder.appendFormalLine(jsonEnabledTypeShortName + " " + jsonBeanName + " = " + jsonEnabledTypeShortName + "." + fromJsonMethodName.getSymbolName() + "(json);"); bodyBuilder.appendFormalLine("if (" + mergeMethod.getMethodCall() + " == null) {"); bodyBuilder.indent(); bodyBuilder .appendFormalLine("return new ResponseEntity<String>(headers, " + getShortName(HTTP_STATUS) + ".NOT_FOUND);"); bodyBuilder.indentRemove(); bodyBuilder.appendFormalLine("}"); bodyBuilder .appendFormalLine("return new ResponseEntity<String>(headers, " + getShortName(HTTP_STATUS) + ".OK);"); if (introduceLayerComponents) { mergeMethod.copyAdditionsTo(builder, governorTypeDetails); } final MethodMetadataBuilder methodBuilder = new MethodMetadataBuilder( getId(), PUBLIC, methodName, RESPONSE_ENTITY_STRING, parameterTypes, parameterNames, bodyBuilder); methodBuilder.setAnnotations(annotations); return methodBuilder; } @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(); } }