package de.jigp.plugin.actions.generator; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.psi.JavaDirectoryService; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiField; import com.intellij.psi.PsiImportList; import com.intellij.psi.PsiImportStatement; import com.intellij.psi.PsiJavaCodeReferenceElement; import com.intellij.psi.PsiJavaFile; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiReferenceList; import de.jigp.plugin.actions.menu.PsiInfrastructureHolder; import org.apache.commons.lang.StringUtils; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.regex.Pattern; public abstract class AbstractGenerator extends PsiInfrastructureHolder { protected final String targetClassSuffix; protected final PsiClass sourceClassForGeneration; private PsiImportList targetImportList; private PsiClass targetClass; private PsiReferenceList targetImplementsList; private PsiReferenceList targetExtendsList; private boolean shouldTargetClassInheritingSource; private boolean isTargetInnerClass; public AbstractGenerator(DataContext dataContext, String targetClassSuffix, PsiClass sourceClass, boolean isTargetClassImplementingSource, boolean isTargetInnerClass) { super(dataContext); this.targetClassSuffix = targetClassSuffix; this.sourceClassForGeneration = sourceClass; this.shouldTargetClassInheritingSource = isTargetClassImplementingSource; this.isTargetInnerClass = isTargetInnerClass; } public PsiClass build() { try { return generate(); } catch (CancelActionException e) { return null; } } private PsiClass generate() throws CancelActionException { initOrCreateTargetClass(); modifyTargetClass(); addTargetClassPhysically(); return targetClass; } private void initOrCreateTargetClass() { if (this.isTargetInnerClass) { createEmptyInnerTargetClass(); } else { createEmptyTargetClass(); } initTargetClassData(); } private PsiClass modifyTargetClass() throws CancelActionException { beforeHandlingHook(); handleMethods(); handleFields(); afterHandlingHook(); addClassInheritance(); addNewFields(); reformatCode(); return targetClass; } private void addTargetClassPhysically() { if (this.isTargetInnerClass) { PsiClass innerClassByName = sourceClassForGeneration.findInnerClassByName(this.targetClassName(), false); if (innerClassByName == null) { sourceClassForGeneration.add(targetClass); } } else { // not inner classes are allready created and updated } } private void createEmptyInnerTargetClass() { targetClass = sourceClassForGeneration.findInnerClassByName(this.targetClassName(), false); if (targetClass == null) { targetClass = psiElementFactory.createClass(targetClassName()); targetClass.getModifierList().setModifierProperty("static", true); } } private void addClassInheritance() { if (shouldTargetClassInheritingSource) { if (sourceClassForGeneration.isInterface()) { addImplementsSourceInterface(targetImplementsList); } else { addImplementsSourceInterface(targetExtendsList); } } } private void reformatCode() { if (codeStyleManager != null) { codeStyleManager.reformat(targetClass); } } private void addImplementsSourceInterface(PsiReferenceList targetList) { PsiJavaCodeReferenceElement newImportListType = psiElementFactory.createReferenceElementByType(psiElementFactory.createType(sourceClassForGeneration)); PsiJavaCodeReferenceElement[] referenceElements = targetList.getReferenceElements(); boolean implementsNecessary = true; for (PsiJavaCodeReferenceElement referenceElement : referenceElements) { if (referenceElement.getQualifiedName().equals(newImportListType.getQualifiedName())) { implementsNecessary = false; break; } } if (implementsNecessary) { targetList.add(newImportListType); } } private void handleMethods() { PsiMethod[] psiMethods = sourceClassForGeneration.getAllMethods(); Collection<PsiMethod> filterdMethods = filterMethodsToHandle(psiMethods); if (filterdMethods == null) { return; } for (PsiMethod psiMethod : filterdMethods) { handleMethod(psiMethod); } } protected List<PsiMethod> filterGetterMethods(PsiMethod[] psiMethods) { List<PsiMethod> getterMethods = new ArrayList<PsiMethod>(); for (PsiMethod psiMethod : psiMethods) { if (isGetter(psiMethod)) { getterMethods.add(psiMethod); } } return getterMethods; } private void handleFields() throws CancelActionException { PsiField[] psiFields = sourceClassForGeneration.getAllFields(); Collection<PsiField> filteredFields = filterFieldsToHandle(psiFields); if (filteredFields == null) { return; } for (PsiField psiField : filteredFields) { handleField(psiField); } } protected void appendReturnTypeToImportList(PsiMethod psiMethod) { PsiClass importClass = psiFacade.findClass(psiMethod.getReturnType().getCanonicalText(), globalSearchScope); appendClassToImportList(importClass); } protected String determineFieldNameFromGetterMethod(PsiMethod psiMethod) { String attributeName = StringUtils.lowerCase(psiMethod.getName().substring(3, 4)) + psiMethod.getName().substring(4); attributeName = JavaLanguageSupport.transformToValidAttributeName(attributeName); return attributeName; } protected PsiMethod addOrReplaceMethod(String methodText) { return addOrReplaceMethod(targetClass, methodText); } protected PsiMethod addOrReplaceMethod(PsiClass target, String methodText) { PsiMethod newMethod = psiElementFactory.createMethodFromText(methodText, null); PsiMethod existingMethod = target.findMethodBySignature(newMethod, false); if (existingMethod != null) { existingMethod.replace(newMethod); } else { target.add(newMethod); } return newMethod; } protected void appendClassToImportList(PsiClass importClass) { if (importClass == null) { return; } PsiImportStatement newImportStatement = psiElementFactory.createImportStatement(importClass); boolean isImportNew = true; for (PsiImportStatement importStatement : targetImportList.getImportStatements()) { if (importStatement.getText().equals(newImportStatement.getText())) { isImportNew = false; } } if (isImportNew) { targetImportList.add(newImportStatement); } } private boolean isGetter(PsiMethod psiMethod) { return isGetter(psiMethod.getName()); } public boolean isGetter(String methodName) { boolean startsWithGet = Pattern.matches("get[A-Z].*", methodName); return startsWithGet && !"getClass".equals(methodName); } protected void addField(PsiField newField) { PsiField existingField = targetClass.findFieldByName(newField.getName(), false); if (existingField != null) { existingField.replace(newField); } else { targetClass.add(newField); } } private void createEmptyTargetClass() { targetClass = psiFacade.findClass(qualifiedTargetClassName(), globalSearchScope); if (targetClass == null) { PsiDirectory sourceClassDirectory = sourceClassForGeneration.getContainingFile().getContainingDirectory(); targetClass = JavaDirectoryService.getInstance().createClass(sourceClassDirectory, targetClassName()); } } private void initTargetClassData() { PsiJavaFile targetJavaFile = (PsiJavaFile) targetClass.getContainingFile(); targetImportList = targetJavaFile.getImportList(); targetImplementsList = targetClass.getImplementsList(); targetExtendsList = targetClass.getExtendsList(); } public String qualifiedTargetClassName() { return sourceClassForGeneration.getQualifiedName() + targetClassSuffix; } public String targetClassName() { return createTargetClassName(sourceClassForGeneration.getName()); } public String createTargetClassName(String name) { return name + targetClassSuffix; } protected abstract Collection<PsiMethod> filterMethodsToHandle(PsiMethod[] psiMethods); protected abstract Collection<PsiField> filterFieldsToHandle(PsiField[] psiFields) throws CancelActionException; protected abstract void beforeHandlingHook(); protected abstract void handleMethod(PsiMethod psiMethod); protected abstract void handleField(PsiField psiField); protected abstract void afterHandlingHook(); protected abstract void addNewFields(); protected String determineGetterMethodNameFromGetterMethod(PsiMethod psiMethod) { return psiMethod.getName(); } protected String determineSetterMethodNameFromGetterMethod(PsiMethod psiMethod) { String setterName = determineGetterMethodNameFromGetterMethod(psiMethod).replaceFirst("g", "s"); return setterName; } protected String determineAddMethodNameFromGetterMethod(PsiMethod psiMethod) { String addName = determineGetterMethodNameFromGetterMethod(psiMethod).replaceFirst("get", "add")+"Element"; return addName; } protected String determineRemoveMethodNameFromGetterMethod(PsiMethod psiMethod) { String removeName = determineAddMethodNameFromGetterMethod(psiMethod).replaceFirst("add", "remove"); return removeName; } protected String determineFieldTypeNameFromGetterMethod(PsiMethod psiMethod) { return psiMethod.getReturnType().getCanonicalText(); } protected String convertFieldTypeToNonPrimitive(PsiMethod psiMethod) { return JavaLanguageSupport.convertToNonPrimitive(psiMethod.getReturnType()); } }