package org.springframework.roo.addon.gwt; import static org.springframework.roo.model.JavaType.LONG_OBJECT; import static org.springframework.roo.model.JdkJavaType.BIG_DECIMAL; import static org.springframework.roo.model.JdkJavaType.DATE; import static org.springframework.roo.model.JdkJavaType.LIST; import static org.springframework.roo.model.JdkJavaType.SET; import static org.springframework.roo.model.JpaJavaType.EMBEDDABLE; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Timer; import java.util.TimerTask; import java.util.logging.Logger; import javax.xml.parsers.DocumentBuilder; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.Service; import org.springframework.roo.addon.gwt.scaffold.GwtScaffoldMetadata; import org.springframework.roo.classpath.PhysicalTypeCategory; import org.springframework.roo.classpath.PhysicalTypeIdentifier; import org.springframework.roo.classpath.PhysicalTypeMetadata; import org.springframework.roo.classpath.TypeLocationService; import org.springframework.roo.classpath.customdata.CustomDataKeys; import org.springframework.roo.classpath.details.AbstractIdentifiableAnnotatedJavaStructureBuilder; import org.springframework.roo.classpath.details.BeanInfoUtils; import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetails; import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetailsBuilder; import org.springframework.roo.classpath.details.ConstructorMetadata; import org.springframework.roo.classpath.details.ConstructorMetadataBuilder; import org.springframework.roo.classpath.details.FieldMetadataBuilder; import org.springframework.roo.classpath.details.IdentifiableAnnotatedJavaStructure; import org.springframework.roo.classpath.details.MemberHoldingTypeDetails; 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.AnnotationAttributeValue; import org.springframework.roo.classpath.details.annotations.AnnotationMetadata; import org.springframework.roo.classpath.itd.InvocableMemberBodyBuilder; import org.springframework.roo.classpath.persistence.PersistenceMemberLocator; import org.springframework.roo.classpath.scanner.MemberDetails; import org.springframework.roo.classpath.scanner.MemberDetailsScanner; import org.springframework.roo.file.monitor.event.FileDetails; import org.springframework.roo.metadata.MetadataService; import org.springframework.roo.model.DataType; import org.springframework.roo.model.JavaPackage; import org.springframework.roo.model.JavaSymbolName; import org.springframework.roo.model.JavaType; import org.springframework.roo.model.RooJavaType; import org.springframework.roo.process.manager.FileManager; import org.springframework.roo.project.LogicalPath; import org.springframework.roo.project.Path; import org.springframework.roo.project.ProjectOperations; import org.springframework.roo.support.logging.HandlerUtils; import org.springframework.roo.support.util.FileUtils; import org.springframework.roo.support.util.XmlUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; /** * Provides a basic implementation of {@link GwtTypeService}. * * @author James Tyrrell * @since 1.1.2 */ @Component @Service public class GwtTypeServiceImpl implements GwtTypeService { private static final Logger LOGGER = HandlerUtils .getLogger(GwtTypeServiceImpl.class); private static final String PATH = "path"; @Reference private FileManager fileManager; @Reference private GwtFileManager gwtFileManager; @Reference private MemberDetailsScanner memberDetailsScanner; @Reference private MetadataService metadataService; @Reference private PersistenceMemberLocator persistenceMemberLocator; @Reference private ProjectOperations projectOperations; @Reference private TypeLocationService typeLocationService; private final Set<String> warnings = new LinkedHashSet<String>(); private final Timer warningTimer = new Timer(); public void addSourcePath(final String sourcePath, final String moduleName) { final String gwtXmlPath = getGwtModuleXml(moduleName); Validate.notBlank(gwtXmlPath, "gwt.xml could not be found for module '" + moduleName + "'"); final Document gwtXmlDoc = getGwtXmlDocument(gwtXmlPath); final Element gwtXmlRoot = gwtXmlDoc.getDocumentElement(); final List<Element> sourceElements = XmlUtils.findElements( "/module/source", gwtXmlRoot); if (!anyExistingSourcePathsIncludePath(sourcePath, sourceElements)) { final Element firstSourceElement = sourceElements.get(0); final Element newSourceElement = gwtXmlDoc.createElement("source"); newSourceElement.setAttribute(PATH, sourcePath); gwtXmlRoot.insertBefore(newSourceElement, firstSourceElement); fileManager.createOrUpdateTextFileIfRequired(gwtXmlPath, XmlUtils.nodeToString(gwtXmlDoc), "Added source paths to gwt.xml file", true); } } private boolean anyExistingSourcePathsIncludePath(final String sourcePath, final Iterable<Element> sourceElements) { for (final Element sourceElement : sourceElements) { if (sourcePath.startsWith(sourceElement.getAttribute(PATH))) { return true; } } return false; } public List<ClassOrInterfaceTypeDetails> buildType(final GwtType destType, final ClassOrInterfaceTypeDetails templateClass, final List<MemberHoldingTypeDetails> extendsTypes, final String moduleName) { try { // A type may consist of a concrete type which depend on final List<ClassOrInterfaceTypeDetails> types = new ArrayList<ClassOrInterfaceTypeDetails>(); final ClassOrInterfaceTypeDetailsBuilder templateClassBuilder = new ClassOrInterfaceTypeDetailsBuilder( templateClass); if (destType.isCreateAbstract()) { final ClassOrInterfaceTypeDetailsBuilder abstractClassBuilder = createAbstractBuilder( templateClassBuilder, extendsTypes, moduleName); final ArrayList<FieldMetadataBuilder> fieldsToRemove = new ArrayList<FieldMetadataBuilder>(); for (final JavaSymbolName fieldName : destType .getWatchedFieldNames()) { for (final FieldMetadataBuilder fieldBuilder : templateClassBuilder .getDeclaredFields()) { if (fieldBuilder.getFieldName().equals(fieldName)) { final FieldMetadataBuilder abstractFieldBuilder = new FieldMetadataBuilder( abstractClassBuilder .getDeclaredByMetadataId(), fieldBuilder.build()); abstractClassBuilder .addField(convertModifier(abstractFieldBuilder)); fieldsToRemove.add(fieldBuilder); break; } } } templateClassBuilder.getDeclaredFields().removeAll( fieldsToRemove); final List<MethodMetadataBuilder> methodsToRemove = new ArrayList<MethodMetadataBuilder>(); for (final JavaSymbolName methodName : destType .getWatchedMethods().keySet()) { for (final MethodMetadataBuilder methodBuilder : templateClassBuilder .getDeclaredMethods()) { final List<JavaType> params = new ArrayList<JavaType>(); for (final AnnotatedJavaType param : methodBuilder .getParameterTypes()) { params.add(new JavaType(param.getJavaType() .getFullyQualifiedTypeName())); } if (methodBuilder.getMethodName().equals(methodName)) { if (destType.getWatchedMethods().get(methodName) .containsAll(params)) { final MethodMetadataBuilder abstractMethodBuilder = new MethodMetadataBuilder( abstractClassBuilder .getDeclaredByMetadataId(), methodBuilder.build()); abstractClassBuilder .addMethod(convertModifier(abstractMethodBuilder)); methodsToRemove.add(methodBuilder); break; } } } } templateClassBuilder.removeAll(methodsToRemove); for (final JavaType innerTypeName : destType .getWatchedInnerTypes()) { for (final ClassOrInterfaceTypeDetailsBuilder innerTypeBuilder : templateClassBuilder .getDeclaredInnerTypes()) { if (innerTypeBuilder .getName() .getFullyQualifiedTypeName() .equals(innerTypeName .getFullyQualifiedTypeName())) { final ClassOrInterfaceTypeDetailsBuilder builder = new ClassOrInterfaceTypeDetailsBuilder( abstractClassBuilder .getDeclaredByMetadataId(), innerTypeBuilder.build()); builder.setName(new JavaType( innerTypeBuilder.getName() .getSimpleTypeName() + "_Roo_Gwt", 0, DataType.TYPE, null, innerTypeBuilder .getName().getParameters())); templateClassBuilder.getDeclaredInnerTypes() .remove(innerTypeBuilder); if (innerTypeBuilder.getPhysicalTypeCategory() .equals(PhysicalTypeCategory.INTERFACE)) { final ClassOrInterfaceTypeDetailsBuilder interfaceInnerTypeBuilder = new ClassOrInterfaceTypeDetailsBuilder( innerTypeBuilder.build()); abstractClassBuilder.addInnerType(builder); templateClassBuilder.getDeclaredInnerTypes() .remove(innerTypeBuilder); interfaceInnerTypeBuilder .clearDeclaredMethods(); interfaceInnerTypeBuilder .getDeclaredInnerTypes().clear(); interfaceInnerTypeBuilder.getExtendsTypes() .clear(); interfaceInnerTypeBuilder .getExtendsTypes() .add(new JavaType( builder.getName() .getSimpleTypeName(), 0, DataType.TYPE, null, Collections .singletonList(new JavaType( "V", 0, DataType.VARIABLE, null, new ArrayList<JavaType>())))); templateClassBuilder.getDeclaredInnerTypes() .add(interfaceInnerTypeBuilder); } break; } } } abstractClassBuilder.setImplementsTypes(templateClass .getImplementsTypes()); templateClassBuilder.getImplementsTypes().clear(); templateClassBuilder.getExtendsTypes().clear(); templateClassBuilder.getExtendsTypes().add( abstractClassBuilder.getName()); types.add(abstractClassBuilder.build()); } types.add(templateClassBuilder.build()); return types; } catch (final Exception e) { throw new IllegalStateException(e); } } public void buildType(final GwtType type, final List<ClassOrInterfaceTypeDetails> templateTypeDetails, final String moduleName) { if (GwtType.LIST_PLACE_RENDERER.equals(type)) { final Map<JavaSymbolName, List<JavaType>> watchedMethods = new HashMap<JavaSymbolName, List<JavaType>>(); watchedMethods.put(new JavaSymbolName("render"), Collections .singletonList(new JavaType(projectOperations .getTopLevelPackage(moduleName) .getFullyQualifiedPackageName() + ".client.scaffold.place.ProxyListPlace"))); type.setWatchedMethods(watchedMethods); } else { type.resolveMethodsToWatch(type); } type.resolveWatchedFieldNames(type); final List<ClassOrInterfaceTypeDetails> typesToBeWritten = new ArrayList<ClassOrInterfaceTypeDetails>(); for (final ClassOrInterfaceTypeDetails templateTypeDetail : templateTypeDetails) { typesToBeWritten.addAll(buildType(type, templateTypeDetail, getExtendsTypes(templateTypeDetail), moduleName)); } gwtFileManager.write(typesToBeWritten, type.isOverwriteConcrete()); } private void checkPrimitive(final JavaType type) { if (type.isPrimitive() && !JavaType.VOID_PRIMITIVE.equals(type)) { final String to = type.getSimpleTypeName(); final String from = to.toLowerCase(); throw new IllegalStateException( "GWT does not currently support primitive types in an entity. Please change any '" + from + "' entity property types to 'java.lang." + to + "'."); } } private <T extends AbstractIdentifiableAnnotatedJavaStructureBuilder<? extends IdentifiableAnnotatedJavaStructure>> T convertModifier( final T builder) { if (Modifier.isPrivate(builder.getModifier())) { builder.setModifier(Modifier.PROTECTED); } return builder; } private ClassOrInterfaceTypeDetailsBuilder createAbstractBuilder( final ClassOrInterfaceTypeDetailsBuilder concreteClass, final List<MemberHoldingTypeDetails> extendsTypesDetails, final String moduleName) { final JavaType concreteType = concreteClass.getName(); String abstractName = concreteType.getSimpleTypeName() + "_Roo_Gwt"; abstractName = concreteType.getPackage().getFullyQualifiedPackageName() + '.' + abstractName; final JavaType abstractType = new JavaType(abstractName); final String abstractId = PhysicalTypeIdentifier.createIdentifier( abstractType, LogicalPath.getInstance(Path.SRC_MAIN_JAVA, moduleName)); final ClassOrInterfaceTypeDetailsBuilder cidBuilder = new ClassOrInterfaceTypeDetailsBuilder( abstractId); cidBuilder.setPhysicalTypeCategory(PhysicalTypeCategory.CLASS); cidBuilder.setName(abstractType); cidBuilder.setModifier(Modifier.ABSTRACT | Modifier.PUBLIC); cidBuilder.getExtendsTypes().addAll(concreteClass.getExtendsTypes()); cidBuilder.add(concreteClass.getRegisteredImports()); for (final MemberHoldingTypeDetails extendsTypeDetails : extendsTypesDetails) { for (final ConstructorMetadata constructor : extendsTypeDetails .getDeclaredConstructors()) { final ConstructorMetadataBuilder abstractConstructor = new ConstructorMetadataBuilder( abstractId); abstractConstructor.setModifier(constructor.getModifier()); final Map<JavaSymbolName, JavaType> typeMap = resolveTypes( extendsTypeDetails.getName(), concreteClass .getExtendsTypes().get(0)); for (final AnnotatedJavaType type : constructor .getParameterTypes()) { JavaType newType = type.getJavaType(); if (type.getJavaType().getParameters().size() > 0) { final ArrayList<JavaType> parameterTypes = new ArrayList<JavaType>(); for (final JavaType typeType : type.getJavaType() .getParameters()) { final JavaType typeParam = typeMap .get(new JavaSymbolName(typeType.toString())); if (typeParam != null) { parameterTypes.add(typeParam); } } newType = new JavaType(type.getJavaType() .getFullyQualifiedTypeName(), type .getJavaType().getArray(), type.getJavaType() .getDataType(), type.getJavaType().getArgName(), parameterTypes); } abstractConstructor.getParameterTypes().add( new AnnotatedJavaType(newType)); } abstractConstructor.setParameterNames(constructor .getParameterNames()); final InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder(); bodyBuilder.newLine().indent().append("super("); int i = 0; for (final JavaSymbolName paramName : abstractConstructor .getParameterNames()) { bodyBuilder.append(" ").append(paramName.getSymbolName()); if (abstractConstructor.getParameterTypes().size() > i + 1) { bodyBuilder.append(", "); } i++; } bodyBuilder.append(");"); bodyBuilder.newLine().indentRemove(); abstractConstructor.setBodyBuilder(bodyBuilder); cidBuilder.getDeclaredConstructors().add(abstractConstructor); } } return cidBuilder; } private void displayWarning(final String warning) { if (!warnings.contains(warning)) { warnings.add(warning); LOGGER.severe(warning); warningTimer.schedule(new TimerTask() { @Override public void run() { warnings.clear(); } }, 15000); } } public List<MemberHoldingTypeDetails> getExtendsTypes( final ClassOrInterfaceTypeDetails childType) { final List<MemberHoldingTypeDetails> extendsTypes = new ArrayList<MemberHoldingTypeDetails>(); if (childType != null) { for (final JavaType javaType : childType.getExtendsTypes()) { final String superTypeId = typeLocationService .getPhysicalTypeIdentifier(javaType); if (superTypeId == null || metadataService.get(superTypeId) == null) { continue; } final MemberHoldingTypeDetails superType = ((PhysicalTypeMetadata) metadataService .get(superTypeId)).getMemberHoldingTypeDetails(); extendsTypes.add(superType); } } return extendsTypes; } public String getGwtModuleXml(final String moduleName) { final LogicalPath logicalPath = LogicalPath.getInstance( Path.SRC_MAIN_JAVA, moduleName); final String gwtModuleXml = projectOperations.getPathResolver() .getRoot(logicalPath) + File.separatorChar + projectOperations.getTopLevelPackage(moduleName) .getFullyQualifiedPackageName() .replace('.', File.separatorChar) + File.separator + "*.gwt.xml"; final Set<String> paths = new LinkedHashSet<String>(); for (final FileDetails fileDetails : fileManager .findMatchingAntPath(gwtModuleXml)) { paths.add(fileDetails.getCanonicalPath()); } if (paths.isEmpty()) { throw new IllegalStateException( "Each module must have a gwt.xml file"); } if (paths.size() > 1) { throw new IllegalStateException( "Each module can only have only gwt.xml file: " + paths.size()); } return paths.iterator().next(); } /** * Return the type arg for the client side method, given the domain method * return type. If domain method return type is List<Integer> or * Set<Integer>, returns the same. If domain method return type is * List<Employee>, return List<EmployeeProxy> * * @param returnType * @param projectMetadata * @param governorType * @return the GWT side leaf type as a JavaType */ public JavaType getGwtSideLeafType(final JavaType returnType, final JavaType governorType, final boolean requestType, final boolean convertPrimitive) { if (returnType.isPrimitive() && convertPrimitive) { if (!requestType) { checkPrimitive(returnType); } return GwtUtils.convertPrimitiveType(returnType, requestType); } if (isTypeCommon(returnType)) { return returnType; } if (isCollectionType(returnType)) { final List<JavaType> args = returnType.getParameters(); if (args != null && args.size() == 1) { final JavaType elementType = args.get(0); final JavaType convertedJavaType = getGwtSideLeafType( elementType, governorType, requestType, convertPrimitive); if (convertedJavaType == null) { return null; } return new JavaType(returnType.getFullyQualifiedTypeName(), 0, DataType.TYPE, null, Arrays.asList(convertedJavaType)); } return returnType; } final ClassOrInterfaceTypeDetails ptmd = typeLocationService .getTypeDetails(returnType); if (isDomainObject(returnType, ptmd)) { if (isEmbeddable(ptmd)) { throw new IllegalStateException( "GWT does not currently support embedding objects in entities, such as '" + returnType.getSimpleTypeName() + "' in '" + governorType.getSimpleTypeName() + "'."); } final ClassOrInterfaceTypeDetails typeDetails = typeLocationService .getTypeDetails(returnType); if (typeDetails == null) { return null; } final ClassOrInterfaceTypeDetails proxy = lookupProxyFromEntity(typeDetails); if (proxy == null) { return null; } return proxy.getName(); } return returnType; } public Document getGwtXmlDocument(final String gwtModuleCanonicalPath) { final DocumentBuilder builder = XmlUtils.getDocumentBuilder(); builder.setEntityResolver(new EntityResolver() { public InputSource resolveEntity(final String publicId, final String systemId) throws SAXException, IOException { if (systemId.endsWith("gwt-module.dtd")) { return new InputSource(FileUtils.getInputStream( GwtScaffoldMetadata.class, "templates/gwt-module.dtd")); } // Use the default behaviour return null; } }); InputStream inputStream = null; try { inputStream = fileManager.getInputStream(gwtModuleCanonicalPath); return builder.parse(inputStream); } catch (final Exception e) { throw new IllegalStateException(e); } finally { IOUtils.closeQuietly(inputStream); } } public List<MethodMetadata> getProxyMethods( final ClassOrInterfaceTypeDetails governorTypeDetails) { final List<MethodMetadata> proxyMethods = new ArrayList<MethodMetadata>(); final MemberDetails memberDetails = memberDetailsScanner .getMemberDetails(GwtTypeServiceImpl.class.getName(), governorTypeDetails); for (final MemberHoldingTypeDetails memberHoldingTypeDetails : memberDetails .getDetails()) { for (final MethodMetadata method : memberDetails.getMethods()) { if (!proxyMethods.contains(method) && isPublicAccessor(method) && isValidMethodReturnType(method, memberHoldingTypeDetails)) { if (method .getCustomData() .keySet() .contains(CustomDataKeys.IDENTIFIER_ACCESSOR_METHOD)) { proxyMethods.add(0, method); } else { proxyMethods.add(method); } } } } return proxyMethods; } public JavaType getServiceLocator(final String moduleName) { return new JavaType(projectOperations.getTopLevelPackage(moduleName) + ".server.locator.GwtServiceLocator"); } public Collection<JavaPackage> getSourcePackages(final String moduleName) { final Document gwtXmlDoc = getGwtXmlDocument(getGwtModuleXml(moduleName)); final Element gwtXmlRoot = gwtXmlDoc.getDocumentElement(); final JavaPackage topLevelPackage = projectOperations .getTopLevelPackage(moduleName); final Collection<JavaPackage> sourcePackages = new HashSet<JavaPackage>(); for (final Element sourcePathElement : XmlUtils.findElements( "/module/source", gwtXmlRoot)) { final String relativePackage = sourcePathElement.getAttribute(PATH) .replace(GwtOperations.PATH_DELIMITER, "."); sourcePackages.add(new JavaPackage(topLevelPackage + "." + relativePackage)); } return sourcePackages; } private boolean isAllowableReturnType(final JavaType type) { return isCommonType(type) || isEntity(type) || isEnum(type); } private boolean isAllowableReturnType(final MethodMetadata method) { return isAllowableReturnType(method.getReturnType()); } private boolean isCollectionType(final JavaType returnType) { return returnType.getFullyQualifiedTypeName().equals( LIST.getFullyQualifiedTypeName()) || returnType.getFullyQualifiedTypeName().equals( SET.getFullyQualifiedTypeName()); } private boolean isCommonType(final JavaType type) { return isTypeCommon(type) || isCollectionType(type) && type.getParameters().size() == 1 && isAllowableReturnType(type.getParameters().get(0)); } public boolean isDomainObject(final JavaType type) { final ClassOrInterfaceTypeDetails ptmd = typeLocationService .getTypeDetails(type); return isDomainObject(type, ptmd); } private boolean isDomainObject(final JavaType returnType, final ClassOrInterfaceTypeDetails ptmd) { return !isEnum(ptmd) && isEntity(returnType) && !isRequestFactoryCompatible(returnType) && !isEmbeddable(ptmd); } private boolean isEmbeddable(final ClassOrInterfaceTypeDetails ptmd) { if (ptmd == null) { return false; } final AnnotationMetadata annotationMetadata = ptmd .getAnnotation(EMBEDDABLE); return annotationMetadata != null; } private boolean isEntity(final JavaType type) { return persistenceMemberLocator.getIdentifierFields(type).size() == 1; } private boolean isEnum(final ClassOrInterfaceTypeDetails ptmd) { return ptmd != null && ptmd.getPhysicalTypeCategory() == PhysicalTypeCategory.ENUMERATION; } private boolean isEnum(final JavaType type) { return isEnum(typeLocationService.getTypeDetails(type)); } public boolean isMethodReturnTypeInSourcePath(final MethodMetadata method, final MemberHoldingTypeDetails memberHoldingTypeDetail, final Iterable<JavaPackage> sourcePackages) { final JavaType returnType = method.getReturnType(); final boolean inSourcePath = isTypeInAnySourcePackage(returnType, sourcePackages); if (!inSourcePath && !isCommonType(returnType) && !JavaType.VOID_PRIMITIVE.getFullyQualifiedTypeName().equals( returnType.getFullyQualifiedTypeName())) { displayWarning("The path to type " + returnType.getFullyQualifiedTypeName() + " which is used in type " + memberHoldingTypeDetail.getName() + " by the field '" + method.getMethodName().getSymbolName() + "' needs to be added to the module's gwt.xml file in order to be used in a Proxy."); return false; } return true; } private boolean isPrimitive(final JavaType type) { return type.isPrimitive() || isCollectionType(type) && type.getParameters().size() == 1 && isPrimitive(type.getParameters().get(0)); } private boolean isPublicAccessor(final MethodMetadata method) { return Modifier.isPublic(method.getModifier()) && !method.getReturnType().equals(JavaType.VOID_PRIMITIVE) && method.getParameterTypes().isEmpty() && method.getMethodName().getSymbolName().startsWith("get"); } private boolean isRequestFactoryCompatible(final JavaType type) { return isCommonType(type) || isCollectionType(type); } private boolean isTypeCommon(final JavaType type) { return JavaType.BOOLEAN_OBJECT.equals(type) || JavaType.CHAR_OBJECT.equals(type) || JavaType.BYTE_OBJECT.equals(type) || JavaType.SHORT_OBJECT.equals(type) || JavaType.INT_OBJECT.equals(type) || LONG_OBJECT.equals(type) || JavaType.FLOAT_OBJECT.equals(type) || JavaType.DOUBLE_OBJECT.equals(type) || JavaType.STRING.equals(type) || DATE.equals(type) || BIG_DECIMAL.equals(type) || type.isPrimitive() && !JavaType.VOID_PRIMITIVE.getFullyQualifiedTypeName().equals( type.getFullyQualifiedTypeName()); } private boolean isTypeInAnySourcePackage(final JavaType type, final Iterable<JavaPackage> sourcePackages) { for (final JavaPackage sourcePackage : sourcePackages) { if (type.getPackage().isWithin(sourcePackage)) { return true; // It's a project type } if (isCollectionType(type) && type.getParameters().size() == 1 && type.getParameters().get(0).getPackage() .isWithin(sourcePackage)) { return true; // It's a collection of a project type } } return false; } private boolean isValidMethodReturnType(final MethodMetadata method, final MemberHoldingTypeDetails memberHoldingTypeDetail) { final JavaType returnType = method.getReturnType(); if (isPrimitive(returnType)) { displayWarning("The primitive field type, " + method.getReturnType().getSimpleTypeName().toLowerCase() + " of '" + method.getMethodName().getSymbolName() + "' in type " + memberHoldingTypeDetail.getName().getSimpleTypeName() + " is not currently support by GWT and will not be added to the scaffolded application."); return false; } final JavaSymbolName propertyName = new JavaSymbolName( StringUtils.uncapitalize(BeanInfoUtils .getPropertyNameForJavaBeanMethod(method) .getSymbolName())); if (!isAllowableReturnType(method)) { displayWarning("The field type " + method.getReturnType().getFullyQualifiedTypeName() + " of '" + method.getMethodName().getSymbolName() + "' in type " + memberHoldingTypeDetail.getName().getSimpleTypeName() + " is not currently support by GWT and will not be added to the scaffolded application."); return false; } if (propertyName.getSymbolName().equals("owner")) { displayWarning("'owner' is not allowed to be used as field name as it is currently reserved by GWT. Please rename the field 'owner' in type " + memberHoldingTypeDetail.getName().getSimpleTypeName() + "."); return false; } return true; } public ClassOrInterfaceTypeDetails lookupEntityFromLocator( final ClassOrInterfaceTypeDetails locator) { Validate.notNull(locator, "Locator is required"); return lookupTargetFromX(locator, RooJavaType.ROO_GWT_LOCATOR); } public ClassOrInterfaceTypeDetails lookupEntityFromProxy( final ClassOrInterfaceTypeDetails proxy) { Validate.notNull(proxy, "Proxy is required"); return lookupTargetFromX(proxy, RooJavaType.ROO_GWT_PROXY); } public ClassOrInterfaceTypeDetails lookupEntityFromRequest( final ClassOrInterfaceTypeDetails request) { Validate.notNull(request, "Request is required"); return lookupTargetFromX(request, RooJavaType.ROO_GWT_REQUEST); } public ClassOrInterfaceTypeDetails lookupProxyFromEntity( final ClassOrInterfaceTypeDetails entity) { return lookupXFromEntity(entity, RooJavaType.ROO_GWT_PROXY); } public ClassOrInterfaceTypeDetails lookupProxyFromRequest( final ClassOrInterfaceTypeDetails request) { final AnnotationMetadata annotation = GwtUtils.getFirstAnnotation( request, RooJavaType.ROO_GWT_REQUEST); Validate.notNull(annotation, "Request '" + request.getName() + "' isn't annotated with '" + RooJavaType.ROO_GWT_REQUEST + "'"); final AnnotationAttributeValue<?> attributeValue = annotation .getAttribute("value"); final JavaType proxyType = new JavaType( GwtUtils.getStringValue(attributeValue)); return lookupProxyFromEntity(typeLocationService .getTypeDetails(proxyType)); } public ClassOrInterfaceTypeDetails lookupRequestFromEntity( final ClassOrInterfaceTypeDetails entity) { return lookupXFromEntity(entity, RooJavaType.ROO_GWT_REQUEST); } public ClassOrInterfaceTypeDetails lookupRequestFromProxy( final ClassOrInterfaceTypeDetails proxy) { final AnnotationMetadata annotation = GwtUtils.getFirstAnnotation( proxy, RooJavaType.ROO_GWT_PROXY); Validate.notNull(annotation, "Proxy '" + proxy.getName() + "' isn't annotated with '" + RooJavaType.ROO_GWT_PROXY + "'"); final AnnotationAttributeValue<?> attributeValue = annotation .getAttribute("value"); final JavaType serviceNameType = new JavaType( GwtUtils.getStringValue(attributeValue)); return lookupRequestFromEntity(typeLocationService .getTypeDetails(serviceNameType)); } public ClassOrInterfaceTypeDetails lookupUnmanagedRequestFromProxy( final ClassOrInterfaceTypeDetails proxy) { final AnnotationMetadata annotation = GwtUtils.getFirstAnnotation( proxy, RooJavaType.ROO_GWT_PROXY); Validate.notNull(annotation, "Proxy '" + proxy.getName() + "' isn't annotated with '" + RooJavaType.ROO_GWT_PROXY + "'"); final AnnotationAttributeValue<?> attributeValue = annotation .getAttribute("value"); final JavaType serviceNameType = new JavaType( GwtUtils.getStringValue(attributeValue)); return lookupUnmanagedRequestFromEntity(typeLocationService .getTypeDetails(serviceNameType)); } public ClassOrInterfaceTypeDetails lookupUnmanagedRequestFromEntity( final ClassOrInterfaceTypeDetails entity) { return lookupXFromEntity(entity, RooJavaType.ROO_GWT_UNMANAGED_REQUEST); } public ClassOrInterfaceTypeDetails lookupTargetFromX( final ClassOrInterfaceTypeDetails annotatedType, final JavaType... annotations) { final AnnotationMetadata annotation = GwtUtils.getFirstAnnotation( annotatedType, annotations); Validate.notNull(annotation, "Type '" + annotatedType.getName() + "' isn't annotated with '" + StringUtils.join(Arrays.asList(annotations), ",") + "'"); final AnnotationAttributeValue<?> attributeValue = annotation .getAttribute("value"); final JavaType targetType = new JavaType( GwtUtils.getStringValue(attributeValue)); return typeLocationService.getTypeDetails(targetType); } public ClassOrInterfaceTypeDetails lookupTargetServiceFromRequest( final ClassOrInterfaceTypeDetails request) { Validate.notNull(request, "Request is required"); return lookupTargetFromX(request, GwtUtils.REQUEST_ANNOTATIONS); } public ClassOrInterfaceTypeDetails lookupXFromEntity( final ClassOrInterfaceTypeDetails entity, final JavaType... annotations) { Validate.notNull(entity, "Entity not found"); for (final ClassOrInterfaceTypeDetails cid : typeLocationService .findClassesOrInterfaceDetailsWithAnnotation(annotations)) { final AnnotationMetadata annotationMetadata = GwtUtils .getFirstAnnotation(cid, annotations); if (annotationMetadata != null) { final AnnotationAttributeValue<?> attributeValue = annotationMetadata .getAttribute("value"); final String value = GwtUtils.getStringValue(attributeValue); if (entity.getName().getFullyQualifiedTypeName().equals(value)) { return cid; } } } return null; } private Map<JavaSymbolName, JavaType> resolveTypes(final JavaType generic, final JavaType typed) { final Map<JavaSymbolName, JavaType> typeMap = new LinkedHashMap<JavaSymbolName, JavaType>(); final boolean typeCountMatch = generic.getParameters().size() == typed .getParameters().size(); Validate.isTrue(typeCountMatch, "Type count must match."); int i = 0; for (final JavaType genericParamType : generic.getParameters()) { typeMap.put(genericParamType.getArgName(), typed.getParameters() .get(i)); i++; } return typeMap; } }