Java tutorial
/* * Copyright 2014 Hippo B.V. (http://www.onehippo.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.onehippo.cms7.essentials.dashboard.services; import java.io.IOException; import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedMap; import java.util.SortedSet; import javax.jcr.RepositoryException; import javax.jcr.Session; import org.apache.commons.io.FilenameUtils; import org.eclipse.jdt.core.dom.AST; import org.eclipse.jdt.core.dom.ASTVisitor; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.SimpleType; import org.eclipse.jdt.core.dom.Type; import org.onehippo.cms7.essentials.dashboard.ctx.PluginContext; import org.onehippo.cms7.essentials.dashboard.event.MessageEvent; import org.onehippo.cms7.essentials.dashboard.model.ActionType; import org.onehippo.cms7.essentials.dashboard.model.BeanWriterLogEntry; import org.onehippo.cms7.essentials.dashboard.utils.BeanWriterUtils; import org.onehippo.cms7.essentials.dashboard.utils.EssentialConst; import org.onehippo.cms7.essentials.dashboard.utils.GlobalUtils; import org.onehippo.cms7.essentials.dashboard.utils.JavaSourceUtils; import org.onehippo.cms7.essentials.dashboard.utils.beansmodel.HippoContentBean; import org.onehippo.cms7.essentials.dashboard.utils.beansmodel.HippoContentChildNode; import org.onehippo.cms7.essentials.dashboard.utils.beansmodel.HippoContentProperty; import org.onehippo.cms7.essentials.dashboard.utils.beansmodel.HippoEssentialsGeneratedObject; import org.onehippo.cms7.essentials.dashboard.utils.code.EssentialsGeneratedMethod; import org.onehippo.cms7.essentials.dashboard.utils.code.ExistingMethodsVisitor; import org.onehippo.cms7.services.contenttype.ContentType; import org.onehippo.cms7.services.contenttype.ContentTypeService; import org.onehippo.cms7.services.contenttype.ContentTypes; import org.onehippo.cms7.services.contenttype.HippoContentTypeService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Predicate; import com.google.common.base.Strings; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; import com.google.common.eventbus.EventBus; /** * @version "$Id$" */ public class ContentBeansService { public static final String HIPPO_GALLERY_IMAGE_SET_BEAN = "HippoGalleryImageSetBean"; public static final String HIPPO_GALLERY_IMAGE_SET_CLASS = "HippoGalleryImageSet"; private static Logger log = LoggerFactory.getLogger(ContentBeansService.class); private final PluginContext context; private final String baseSupertype; private static final String BASE_COMPOUND_TYPE = "hippo:compound"; public static final String MSG_ADDED_METHOD = "@@@ added [{}] method"; public static final String CONTEXT_BEAN_DATA = BeanWriterUtils.class.getName(); public static final String CONTEXT_BEAN_IMAGE_SET = BeanWriterUtils.class.getName() + "imageset"; private final Set<HippoContentBean> contentBeans; /** * How many loops we run (beans extending none existing beans) */ private static final int MISSING_DEPTH_MAX = 5; private int missingBeansDepth = 0; final EventBus eventBus; public ContentBeansService(final PluginContext context, final EventBus eventBus) { this.context = context; this.eventBus = eventBus; this.baseSupertype = context.getProjectNamespacePrefix() + ':' + "basedocument"; this.contentBeans = getContentBeans(); } public void createBeans() throws RepositoryException { final Map<String, Path> existing = findExitingBeans(); final List<HippoContentBean> missingBeans = Lists.newArrayList(filterMissingBeans(existing)); final Iterator<HippoContentBean> missingBeanIterator = missingBeans.iterator(); for (; missingBeanIterator.hasNext();) { final HippoContentBean missingBean = missingBeanIterator.next(); // check if directly extending compound: final Set<String> superTypes = missingBean.getSuperTypes(); if (superTypes.size() == 1 && superTypes.iterator().next().equals(BASE_COMPOUND_TYPE)) { createBaseBean(missingBean); missingBeanIterator.remove(); } else { final String parent = findExistingParent(missingBean, existing); if (parent != null) { log.debug("found parent: {}, {}", parent, missingBean); missingBeanIterator.remove(); createBean(missingBean, existing.get(parent)); } } } // process beans without resolved parent beans processMissing(missingBeans); processProperties(); // check if still missing(beans that extended missing beans) final Iterator<HippoContentBean> extendedMissing = filterMissingBeans(findExitingBeans()); final boolean hasNonCreatedBeans = extendedMissing.hasNext(); if (missingBeansDepth < MISSING_DEPTH_MAX && hasNonCreatedBeans) { missingBeansDepth++; createBeans(); } else if (hasNonCreatedBeans) { log.error("Not all beans were created: {}", extendedMissing); } } private Iterator<HippoContentBean> filterMissingBeans(final Map<String, Path> existing) { final Iterable<HippoContentBean> missingBeans = Iterables.filter(contentBeans, new Predicate<HippoContentBean>() { @Override public boolean apply(HippoContentBean b) { return !existing.containsKey(b.getName()); } }); // process beans with known (project) supertypes: return Lists.newArrayList(missingBeans).iterator(); } private void processProperties() { final Map<String, Path> existing = findExitingBeans(); for (HippoContentBean bean : contentBeans) { final Path beanPath = existing.get(bean.getName()); if (beanPath != null) { final String parent = findExistingParent(bean, existing); final Path parentPath = existing.get(parent); if (parentPath != null) { final ExistingMethodsVisitor parentMethodCollection = JavaSourceUtils .getMethodCollection(parentPath); final ExistingMethodsVisitor ownMethodCollection = JavaSourceUtils .getMethodCollection(beanPath); final Set<String> existingMethods = ownMethodCollection.getMethodInternalNames(); existingMethods.addAll(parentMethodCollection.getMethodInternalNames()); addMethods(bean, beanPath, existingMethods); } else { final ExistingMethodsVisitor ownMethodCollection = JavaSourceUtils .getMethodCollection(beanPath); addMethods(bean, beanPath, ownMethodCollection.getMethodInternalNames()); } } } } private void processMissing(final List<HippoContentBean> missingBeans) { for (HippoContentBean missingBean : missingBeans) { final SortedSet<String> mySupertypes = missingBean.getContentType().getSuperTypes(); if (mySupertypes.contains("hippogallery:relaxed")) { final Path javaClass = createJavaClass(missingBean); JavaSourceUtils.createHippoBean(javaClass, context.beansPackageName(), missingBean.getName(), missingBean.getName()); JavaSourceUtils.addExtendsClass(javaClass, HIPPO_GALLERY_IMAGE_SET_CLASS); JavaSourceUtils.addImport(javaClass, EssentialConst.HIPPO_IMAGE_SET_IMPORT); addMethods(missingBean, javaClass, new ArrayList<String>()); } } } private String findExistingParent(final HippoContentBean missingBean, final Map<String, Path> existing) { final Set<String> superTypes = missingBean.getSuperTypes(); if (superTypes.size() == 1 && superTypes.iterator().next().equals(baseSupertype)) { return baseSupertype; } // extends a document for (String superType : superTypes) { if (!superType.equals(baseSupertype) && existing.containsKey(superType)) { // TODO improve nested types return superType; } } return null; } public final Set<HippoContentBean> getContentBeans() { try { final Set<HippoContentBean> beans = new HashSet<>(); final Set<ContentType> projectContentTypes = getProjectContentTypes(); for (ContentType projectContentType : projectContentTypes) { final HippoContentBean bean = new HippoContentBean(context, projectContentType); beans.add(bean); } return beans; } catch (RepositoryException e) { log.error("Error fetching beans", e); } return Collections.emptySet(); } /** * Fetch project content types * * @return empty collection if no types are found * @throws javax.jcr.RepositoryException */ public Set<ContentType> getProjectContentTypes() throws RepositoryException { final String namespacePrefix = context.getProjectNamespacePrefix(); final Set<ContentType> projectContentTypes = new HashSet<>(); final Session session = context.createSession(); try { final ContentTypeService service = new HippoContentTypeService(session); final ContentTypes contentTypes = service.getContentTypes(); final SortedMap<String, Set<ContentType>> typesByPrefix = contentTypes.getTypesByPrefix(); for (Map.Entry<String, Set<ContentType>> entry : typesByPrefix.entrySet()) { final String key = entry.getKey(); final Set<ContentType> value = entry.getValue(); if (key.equals(namespacePrefix)) { projectContentTypes.addAll(value); return projectContentTypes; } } } finally { GlobalUtils.cleanupSession(session); } return Collections.emptySet(); } //############################################ // UTILS //############################################ private Map<String, Path> findExitingBeans() { final Path startDir = context.getBeansPackagePath(); final Map<String, Path> existingBeans = new HashMap<>(); final List<Path> directories = new ArrayList<>(); GlobalUtils.populateDirectories(startDir, directories); final String pattern = "*.java"; for (Path directory : directories) { try (final DirectoryStream<Path> stream = Files.newDirectoryStream(directory, pattern)) { for (Path path : stream) { final String nodeJcrType = JavaSourceUtils.getNodeJcrType(path); if (nodeJcrType != null) { existingBeans.put(nodeJcrType, path); } } } catch (IOException e) { log.error("Error reading java files", e); } } return existingBeans; } private void createBaseBean(final HippoContentBean bean) { final Path javaClass = createJavaClass(bean); JavaSourceUtils.createHippoBean(javaClass, context.beansPackageName(), bean.getName(), bean.getName()); JavaSourceUtils.addExtendsClass(javaClass, "HippoDocument"); JavaSourceUtils.addImport(javaClass, EssentialConst.HIPPO_DOCUMENT_IMPORT); } private void addMethods(final HippoContentBean bean, final Path beanPath, final Collection<String> existing) { final List<HippoContentProperty> properties = bean.getProperties(); for (HippoContentProperty property : properties) { final String name = property.getName(); if (!hasChange(name, existing, beanPath, property.isMultiple())) { continue; } final String type = property.getType(); log.debug("processing missing property, BEAN: {}, PROPERTY: {}", bean.getName(), property.getName()); if (type == null) { log.error("Missing type for property, cannot create method {}", property.getName()); continue; } final boolean multiple = property.isMultiple(); String methodName; switch (type) { case "String": case "Html": case "Password": case "Docbase": case "Text": methodName = GlobalUtils.createMethodName(name); JavaSourceUtils.addBeanMethodString(beanPath, methodName, name, multiple); existing.add(name); context.addPluginContextData(CONTEXT_BEAN_DATA, new BeanWriterLogEntry(beanPath.toString(), methodName, ActionType.CREATED_METHOD)); log.debug(MSG_ADDED_METHOD, methodName); eventBus.post(new MessageEvent(String.format("Successfully created method: %s", methodName))); break; case "Date": methodName = GlobalUtils.createMethodName(name); JavaSourceUtils.addBeanMethodCalendar(beanPath, methodName, name, multiple); existing.add(name); context.addPluginContextData(CONTEXT_BEAN_DATA, new BeanWriterLogEntry(beanPath.toString(), methodName, ActionType.CREATED_METHOD)); log.debug(MSG_ADDED_METHOD, methodName); eventBus.post(new MessageEvent(String.format("Successfully created method: %s", methodName))); break; case "Boolean": methodName = GlobalUtils.createMethodName(name); JavaSourceUtils.addBeanMethodBoolean(beanPath, methodName, name, multiple); existing.add(name); context.addPluginContextData(CONTEXT_BEAN_DATA, new BeanWriterLogEntry(beanPath.toString(), methodName, ActionType.CREATED_METHOD)); log.debug(MSG_ADDED_METHOD, methodName); eventBus.post(new MessageEvent(String.format("Successfully created method: %s", methodName))); break; case "Long": methodName = GlobalUtils.createMethodName(name); JavaSourceUtils.addBeanMethodLong(beanPath, methodName, name, multiple); existing.add(name); context.addPluginContextData(CONTEXT_BEAN_DATA, new BeanWriterLogEntry(beanPath.toString(), methodName, ActionType.CREATED_METHOD)); log.debug(MSG_ADDED_METHOD, methodName); eventBus.post(new MessageEvent(String.format("Successfully created method: %s", methodName))); break; case "Double": methodName = GlobalUtils.createMethodName(name); JavaSourceUtils.addBeanMethodDouble(beanPath, methodName, name, multiple); existing.add(name); context.addPluginContextData(CONTEXT_BEAN_DATA, new BeanWriterLogEntry(beanPath.toString(), methodName, ActionType.CREATED_METHOD)); log.debug(MSG_ADDED_METHOD, methodName); eventBus.post(new MessageEvent(String.format("Successfully created method: %s", methodName))); break; default: final String message = String.format( "TODO: Beanwriter: Failed to create getter for property: %s of type: %s", property.getName(), type); JavaSourceUtils.addClassJavaDoc(beanPath, message); log.warn(message); break; } } //############################################ // NODE TYPES //############################################ final List<HippoContentChildNode> children = bean.getChildren(); for (HippoContentChildNode child : children) { final String name = child.getName(); if (!hasChange(name, existing, beanPath, child.isMultiple())) { continue; } final String type = child.getType(); log.debug("processing missing node, BEAN: {}, CHILD: {}", bean.getName(), child.getName()); if (type == null) { log.error("Missing type for node, cannot create method {}", child.getName()); continue; } final boolean multiple = child.isMultiple(); String methodName; switch (type) { case "hippostd:html": methodName = GlobalUtils.createMethodName(name); JavaSourceUtils.addBeanMethodHippoHtml(beanPath, methodName, name, multiple); existing.add(name); context.addPluginContextData(CONTEXT_BEAN_DATA, new BeanWriterLogEntry(beanPath.toString(), methodName, ActionType.CREATED_METHOD)); log.debug(MSG_ADDED_METHOD, methodName); break; case "hippogallerypicker:imagelink": methodName = GlobalUtils.createMethodName(name); final Path path = extractPath(); if (path == null) { JavaSourceUtils.addBeanMethodImageLink(beanPath, methodName, name, multiple); } else { final String className = JavaSourceUtils.getClassName(path); final String importName = JavaSourceUtils.getImportName(path); JavaSourceUtils.addBeanMethodInternalImageSet(beanPath, className, importName, methodName, name, multiple); } existing.add(name); context.addPluginContextData(CONTEXT_BEAN_DATA, new BeanWriterLogEntry(beanPath.toString(), methodName, ActionType.CREATED_METHOD)); log.debug(MSG_ADDED_METHOD, methodName); break; case "hippo:mirror": methodName = GlobalUtils.createMethodName(name); JavaSourceUtils.addBeanMethodHippoMirror(beanPath, methodName, name, multiple); existing.add(name); context.addPluginContextData(CONTEXT_BEAN_DATA, new BeanWriterLogEntry(beanPath.toString(), methodName, ActionType.CREATED_METHOD)); log.debug(MSG_ADDED_METHOD, methodName); break; case "hippogallery:image": methodName = GlobalUtils.createMethodName(name); JavaSourceUtils.addBeanMethodHippoImage(beanPath, methodName, name, multiple); existing.add(name); context.addPluginContextData(CONTEXT_BEAN_DATA, new BeanWriterLogEntry(beanPath.toString(), methodName, ActionType.CREATED_METHOD)); log.debug(MSG_ADDED_METHOD, methodName); break; default: // check if project type is used: final String prefix = child.getPrefix(); if (prefix.equals(context.getProjectNamespacePrefix())) { final Map<String, Path> existingBeans = findExitingBeans(); for (Map.Entry<String, Path> entry : existingBeans.entrySet()) { final Path myBeanPath = entry.getValue(); final HippoEssentialsGeneratedObject a = JavaSourceUtils .getHippoGeneratedAnnotation(myBeanPath); if (a != null && a.getInternalName().equals(type)) { final String className = JavaSourceUtils.getClassName(myBeanPath); methodName = GlobalUtils.createMethodName(name); final String importPath = JavaSourceUtils.getImportName(myBeanPath); JavaSourceUtils.addBeanMethodInternalType(beanPath, className, importPath, methodName, name, multiple); context.addPluginContextData(CONTEXT_BEAN_DATA, new BeanWriterLogEntry( beanPath.toString(), methodName, ActionType.CREATED_METHOD)); return; } } } final String message = String.format("TODO: Beanwriter: Failed to create getter for node type: %s", type); JavaSourceUtils.addClassJavaDoc(beanPath, message); log.warn(message); break; } } } private Path extractPath() { final Multimap<String, Object> pluginContextData = context.getPluginContextData(); final Collection<Object> data = pluginContextData.get(CONTEXT_BEAN_IMAGE_SET); Path path = null; if (data != null && data.size() == 1) { final Object next = data.iterator().next(); if (next instanceof Path) { path = (Path) next; } } return path; } public Map<String, Path> getExistingImageTypes() { final Map<String, Path> existing = findExitingBeans(); final Map<String, Path> imageTypes = new HashMap<>(); imageTypes.put(HIPPO_GALLERY_IMAGE_SET_CLASS, null); for (Path path : existing.values()) { final String myClass = JavaSourceUtils.getClassName(path); final String extendsClass = JavaSourceUtils.getExtendsClass(path); if (!Strings.isNullOrEmpty(extendsClass) && extendsClass.equals(HIPPO_GALLERY_IMAGE_SET_CLASS)) { imageTypes.put(myClass, path); } } return imageTypes; } @SuppressWarnings("rawtypes") public void convertImageMethods(final String newImageNamespace) { final Map<String, Path> existing = findExitingBeans(); final Map<String, String> imageTypes = new HashMap<>(); final Set<Path> imageTypePaths = new HashSet<>(); imageTypes.put(HIPPO_GALLERY_IMAGE_SET_CLASS, "org.hippoecm.hst.content.beans.standard.HippoGalleryImageSet"); imageTypes.put(HIPPO_GALLERY_IMAGE_SET_BEAN, "org.hippoecm.hst.content.beans.standard.HippoGalleryImageSetBean"); String newReturnType = null; for (Path path : existing.values()) { final String myClass = JavaSourceUtils.getClassName(path); final String extendsClass = JavaSourceUtils.getExtendsClass(path); final HippoEssentialsGeneratedObject annotation = JavaSourceUtils.getHippoGeneratedAnnotation(path); if (!Strings.isNullOrEmpty(extendsClass) && extendsClass.equals(HIPPO_GALLERY_IMAGE_SET_CLASS)) { imageTypes.put(myClass, JavaSourceUtils.getImportName(path)); imageTypePaths.add(path); } if (annotation != null && newImageNamespace.equals(annotation.getInternalName())) { newReturnType = myClass; } } if (newImageNamespace.equals(HIPPO_GALLERY_IMAGE_SET_BEAN) || newImageNamespace.equals(HIPPO_GALLERY_IMAGE_SET_CLASS)) { newReturnType = HIPPO_GALLERY_IMAGE_SET_CLASS; } if (Strings.isNullOrEmpty(newReturnType)) { log.warn("Could not find return type for image set namespace: {}", newImageNamespace); return; } log.info("Converting existing image beans to new type: {}", newReturnType); for (Map.Entry<String, Path> entry : existing.entrySet()) { // check if image type and skip if so: final Path path = entry.getValue(); if (imageTypePaths.contains(path)) { continue; } final ExistingMethodsVisitor methods = JavaSourceUtils.getMethodCollection(path); final List<EssentialsGeneratedMethod> generatedMethods = methods.getGeneratedMethods(); for (EssentialsGeneratedMethod m : generatedMethods) { final Type type = m.getMethodDeclaration().getReturnType2(); if (type.isSimpleType()) { final SimpleType simpleType = (SimpleType) type; final String returnType = simpleType.getName().getFullyQualifiedName(); // check if image type and different than new return type if (imageTypes.containsKey(returnType) && !returnType.equals(newReturnType)) { log.info("Found image type: {}", returnType); updateImageMethod(path, returnType, newReturnType, imageTypes.get(newReturnType)); } } else if (JavaSourceUtils.getParameterizedType(type) != null) { final String returnType = JavaSourceUtils.getParameterizedType(type); if (imageTypes.containsKey(returnType) && !returnType.equals(newReturnType)) { log.info("Found image type: {}", returnType); updateImageMethod(path, returnType, newReturnType, imageTypes.get(newReturnType)); } } } } } private void updateImageMethod(final Path path, final String oldReturnType, final String newReturnType, final String importStatement) { final CompilationUnit deleteUnit = JavaSourceUtils.getCompilationUnit(path); final ExistingMethodsVisitor methodCollection = JavaSourceUtils.getMethodCollection(path); final List<EssentialsGeneratedMethod> generatedMethods = methodCollection.getGeneratedMethods(); final Map<String, EssentialsGeneratedMethod> deletedMethods = new HashMap<>(); deleteUnit.accept(new ASTVisitor() { @Override public boolean visit(MethodDeclaration node) { final String methodName = node.getName().getFullyQualifiedName(); final Type type = node.getReturnType2(); if (type.isSimpleType()) { final SimpleType simpleType = (SimpleType) type; final String returnTypeName = simpleType.getName().getFullyQualifiedName(); final EssentialsGeneratedMethod method = JavaSourceUtils.extractMethod(methodName, generatedMethods); if (method == null) { return super.visit(node); } if (returnTypeName.equals(oldReturnType)) { node.delete(); deletedMethods.put(method.getMethodName(), method); return super.visit(node); } } else if (JavaSourceUtils.getParameterizedType(type) != null) { final String returnTypeName = JavaSourceUtils.getParameterizedType(type); final EssentialsGeneratedMethod method = JavaSourceUtils.extractMethod(methodName, generatedMethods); if (method == null) { return super.visit(node); } if (returnTypeName.equals(oldReturnType)) { node.delete(); deletedMethods.put(method.getMethodName(), method); return super.visit(node); } log.info("oldReturnType {}", oldReturnType); } return super.visit(node); } }); if (deletedMethods.size() > 0) { final AST deleteAst = deleteUnit.getAST(); final String deletedSource = JavaSourceUtils.rewrite(deleteUnit, deleteAst); GlobalUtils.writeToFile(deletedSource, path); for (Map.Entry<String, EssentialsGeneratedMethod> entry : deletedMethods.entrySet()) { final EssentialsGeneratedMethod oldMethod = entry.getValue(); // Add replacement methods: if (newReturnType.equals(HIPPO_GALLERY_IMAGE_SET_CLASS) || newReturnType.equals(HIPPO_GALLERY_IMAGE_SET_BEAN)) { JavaSourceUtils.addBeanMethodHippoImageSet(path, oldMethod.getMethodName(), oldMethod.getInternalName(), oldMethod.isMultiType()); } else { JavaSourceUtils.addBeanMethodInternalImageSet(path, newReturnType, importStatement, oldMethod.getMethodName(), oldMethod.getInternalName(), oldMethod.isMultiType()); } log.debug("Replaced old method: {} with new return type: {}", oldMethod.getMethodName(), newReturnType); context.addPluginContextData(CONTEXT_BEAN_DATA, new BeanWriterLogEntry(path.toString(), oldMethod.getMethodName(), ActionType.MODIFIED_METHOD)); } } } /** * Create a bean for giving parent bean path * * @param bean none existing bean * @param parentPath existing parent bean */ private void createBean(final HippoContentBean bean, final Path parentPath) { final Path javaClass = createJavaClass(bean); JavaSourceUtils.createHippoBean(javaClass, context.beansPackageName(), bean.getName(), bean.getName()); final String extendsName = FilenameUtils.removeExtension(parentPath.toFile().getName()); JavaSourceUtils.addExtendsClass(javaClass, extendsName); JavaSourceUtils.addImport(javaClass, EssentialConst.HIPPO_DOCUMENT_IMPORT); } private Path createJavaClass(final HippoContentBean bean) { String name = bean.getName(); if (name.indexOf(',') != -1) { name = name.split(",")[0]; } final String className = GlobalUtils.createClassName(name); final Path path = JavaSourceUtils.createJavaClass(context.getSiteJavaRoot(), className, context.beansPackageName(), null); context.addPluginContextData(CONTEXT_BEAN_DATA, new BeanWriterLogEntry(ActionType.CREATED_CLASS, path.toString(), className)); return path; } private boolean hasChange(final String name, final Collection<String> existing, final Path beanPath, final boolean multiple) { if (existing.contains(name)) { log.debug( "Property already exists {}. Checking if method signature has changed e.g. single value to multiple", name); final ExistingMethodsVisitor methodCollection = JavaSourceUtils.getMethodCollection(beanPath); final List<EssentialsGeneratedMethod> generatedMethods = methodCollection.getGeneratedMethods(); for (EssentialsGeneratedMethod generatedMethod : generatedMethods) { final String internalName = generatedMethod.getInternalName(); if (name.equals(internalName)) { // check if single/multiple changed: if (generatedMethod.isMultiType() != multiple) { log.info("Property changed (single/multiple): {}", internalName); return JavaSourceUtils.deleteMethod(generatedMethod, beanPath); } // TODO: check check if signature changed: } } return false; } return true; } }