package com.cedarsoft.serialization.generator.intellij.action; import com.cedarsoft.serialization.generator.intellij.SerializerGenerator; import com.cedarsoft.serialization.generator.intellij.SerializerResolver; import com.cedarsoft.serialization.generator.intellij.SerializerTestsGenerator; import com.cedarsoft.serialization.generator.intellij.jackson.JacksonSerializerGenerator; import com.cedarsoft.serialization.generator.intellij.jackson.JacksonSerializerResolver; import com.cedarsoft.serialization.generator.intellij.jackson.JacksonSerializerTestsGenerator; import com.cedarsoft.serialization.generator.intellij.model.SerializerModel; import com.cedarsoft.serialization.generator.intellij.model.SerializerModelFactory; import com.cedarsoft.serialization.generator.intellij.stax.mate.StaxMateSerializerGenerator; import com.cedarsoft.serialization.generator.intellij.stax.mate.StaxMateSerializerResolver; import com.cedarsoft.serialization.generator.intellij.stax.mate.StaxMateSerializerTestsGenerator; import com.intellij.codeInsight.CodeInsightUtil; import com.intellij.lang.Language; import com.intellij.lang.java.JavaLanguage; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.LangDataKeys; import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ContentEntry; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.roots.SourceFolder; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.JavaDirectoryService; import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementFactory; import com.intellij.psi.PsiField; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; import com.intellij.psi.PsiPackage; import com.intellij.psi.PsiReferenceList; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.refactoring.PackageWrapper; import com.intellij.refactoring.util.RefactoringUtil; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.HashSet; import java.util.List; import java.util.Set; /** * @author Johannes Schneider (<a href="mailto:js@cedarsoft.com">js@cedarsoft.com</a>) */ public class GenerateSerializerAction extends AnAction { @Override public void update( AnActionEvent e ) { super.update( e ); e.getPresentation().setEnabled( getCurrentClass( e ) != null ); //if ( ActionPlaces.isPopupPlace( e.getPlace() ) ) { // e.getPresentation().setVisible( enabled ); //} } public static boolean isAcceptableFile( @Nonnull PsiFile file ) { Language language = file.getLanguage(); return JavaLanguage.INSTANCE.getID().equals( language.getID() ); } @Override public void actionPerformed( AnActionEvent e ) { @Nullable PsiClass psiClass = getCurrentClass( e ); if ( psiClass == null ) { throw new IllegalStateException( "No class found" ); } GenerateSerializerDialog generateSerializerDialog = new GenerateSerializerDialog( psiClass ); generateSerializerDialog.show(); if ( !generateSerializerDialog.isOK() ) { return; } //TODO add error handling, add progress dialog Project project = getEventProject( e ); assert project != null; SerializerResolver serializerResolver = createSerializerResolver( generateSerializerDialog.getSelectedDialect(), project ); SerializerModelFactory serializerModelFactory = new SerializerModelFactory( serializerResolver, JavaCodeStyleManager.getInstance( project ) ); SerializerModel model = serializerModelFactory.create( psiClass, generateSerializerDialog.getSelectedFields() ); SerializerGenerator serializerGenerator = createSerializerGenerator( generateSerializerDialog.getSelectedDialect(), psiClass ); SerializerTestsGenerator testsGenerator = createSerializerTestsGenerator( generateSerializerDialog.getSelectedDialect(), psiClass ); PsiClass serializer = serializerGenerator.generate( model ); testsGenerator.generate( model ); Project serializerProject = serializer.getProject(); @Nullable PsiFile containingFile = serializer.getContainingFile(); if ( containingFile == null ) { throw new IllegalStateException( "--> null file for " + serializer ); } if ( containingFile.getVirtualFile() == null ) { throw new IllegalStateException( "--> null virtual file for " + serializer ); } //Editor editor = CodeInsightUtil.positionCursor( serializerProject, containingFile, serializer.getLBrace() ); //System.out.println( "Finished: " + psiClass ); //JavaPsiFacade psiFacade = JavaPsiFacade.getInstance( project ); // //final Application application = ApplicationManager.getApplication(); // //@javax.annotation.Nullable PsiFile psiFile = PsiManager.getInstance( project ).findFile( file ); //if ( psiFile == null ) { // throw new IllegalStateException( "No psi file found for <" + file + ">" ); //} // // //String name = file.getName(); //PsiFile[] filesByName = FilenameIndex.getFilesByName( project, name, GlobalSearchScope.allScope( project ) ); // //System.out.println( Arrays.toString( filesByName ) ); //PsiFile psiFile = filesByName[0]; // //psiFile.getVirtualFile(); //AnnotatedMembersSearch.search( psiFacade.findClass( annotationName, globalSearchScope ) ); // // //CommandProcessor.getInstance().executeCommand( project, new Runnable() { // @Override // public void run() { // System.out.println( "Running Command" ); // // try { // Thread.sleep( 5000 ); // } catch ( InterruptedException ie ) { // throw new RuntimeException( ie ); // } // // System.out.println( "finished..." ); // } //}, null, null ); } @Nonnull private static SerializerResolver createSerializerResolver( @Nonnull GenerateSerializerDialog.Dialect dialect, @Nonnull Project project ) { switch ( dialect ) { case JACKSON: return new JacksonSerializerResolver( project ); case STAX_MATE: return new StaxMateSerializerResolver( project ); } throw new IllegalArgumentException( "Unsupported dialect " + dialect ); } @Nonnull private static SerializerTestsGenerator createSerializerTestsGenerator( @Nonnull GenerateSerializerDialog.Dialect dialect, @Nonnull PsiClass psiClass ) { switch ( dialect ) { case JACKSON: return new JacksonSerializerTestsGenerator( psiClass.getProject() ); case STAX_MATE: return new StaxMateSerializerTestsGenerator( psiClass.getProject() ); } throw new IllegalArgumentException( "Unsupported dialect " + dialect ); } @Nonnull private static SerializerGenerator createSerializerGenerator( @Nonnull GenerateSerializerDialog.Dialect dialect, @Nonnull PsiClass psiClass ) { switch ( dialect ) { case JACKSON: return new JacksonSerializerGenerator( psiClass.getProject() ); case STAX_MATE: return new StaxMateSerializerGenerator( psiClass.getProject() ); } throw new IllegalArgumentException( "Unsupported dialect " + dialect ); } void generateSerializer( @Nonnull final PsiClass psiClass, @Nonnull List<? extends PsiField> selectedFields ) { System.out.println( "Generating Serializer for: " ); for ( PsiField selectedField : selectedFields ) { System.out.println( "\t" + selectedField.getName() + " - " + selectedField.getType().getPresentableText() ); } PsiFile psiFile = psiClass.getContainingFile(); new WriteCommandAction.Simple( psiClass.getProject(), psiFile ) { @Override protected void run() throws Throwable { PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory( getProject() ); JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance( getProject() ); //StringBuilder builder = new StringBuilder(); //builder.append( "public void deserializeStuff(){" ) // .append( psiClass.getName() ).append( ".class.getName();" ) // .append( "}" ); // //PsiElement method = psiClass.add( elementFactory.createMethodFromText( builder.toString(), psiClass ) ); // //codeStyleManager.shortenClassReferences( method ); PsiReferenceList implementsList = psiClass.getImplementsList(); if ( implementsList == null ) { throw new IllegalStateException( "no implements list found" ); } //PsiElement implementsReference = implementsList.add( elementFactory.createReferenceFromText( "Comparable<" + psiClass.getQualifiedName() + ">", psiClass ) ); //codeStyleManager.shortenClassReferences( implementsReference ); if ( isUnderTestSources( psiClass ) ) { throw new IllegalStateException( "Is a test source!" ); } Module srcModule = ModuleUtilCore.findModuleForPsiElement( psiClass ); if ( srcModule == null ) { throw new IllegalStateException( "No src module found" ); } PsiDirectory srcDir = psiClass.getContainingFile().getContainingDirectory(); PsiPackage srcPackage = JavaDirectoryService.getInstance().getPackage( srcDir ); //PsiClass serializerClass = elementFactory.createClass( psiClass.getQualifiedName() + "Serializer" ); final Set<VirtualFile> testFolders = new HashSet<VirtualFile>(); fillTestRoots( srcModule, testFolders ); if ( testFolders.isEmpty() ) { throw new IllegalStateException( "No test folders found" ); } VirtualFile testFolder = testFolders.iterator().next(); final String packageName = "com.cedarsoft.test.hardcoded.test"; PsiManager psiManager = PsiManager.getInstance( getProject() ); final PackageWrapper targetPackage = new PackageWrapper( psiManager, packageName ); PsiDirectory targetPackageDir = RefactoringUtil.createPackageDirectoryInSourceRoot( targetPackage, testFolder ); PsiClass test = createTest( getProject(), targetPackageDir, psiClass ); Editor editor = CodeInsightUtil.positionCursor( getProject(), test.getContainingFile(), test.getLBrace() ); } }.execute(); } private PsiClass createTest( @Nonnull Project project, @Nonnull PsiDirectory targetDir, @Nonnull PsiClass psiClass ) { IdeDocumentHistory.getInstance( project ).includeCurrentPlaceAsChangePlace(); return JavaDirectoryService.getInstance().createClass( targetDir, psiClass.getName() + "SerializerTest" ); } protected static void fillTestRoots( @Nonnull Module srcModule, @Nonnull Set<VirtualFile> testFolders ) { checkForTestRoots( srcModule, testFolders, new HashSet<Module>() ); } private static void checkForTestRoots( @Nonnull final Module srcModule, @Nonnull final Set<VirtualFile> testFolders, @Nonnull final Set<Module> processed ) { final boolean isFirst = processed.isEmpty(); if ( !processed.add( srcModule ) ) { return; } final ContentEntry[] entries = ModuleRootManager.getInstance( srcModule ).getContentEntries(); for ( ContentEntry entry : entries ) { for ( SourceFolder sourceFolder : entry.getSourceFolders() ) { if ( sourceFolder.isTestSource() ) { final VirtualFile sourceFolderFile = sourceFolder.getFile(); if ( sourceFolderFile != null ) { testFolders.add( sourceFolderFile ); } } } } if ( isFirst && !testFolders.isEmpty() ) { return; } final HashSet<Module> modules = new HashSet<Module>(); ModuleUtilCore.collectModulesDependsOn( srcModule, modules ); for ( Module module : modules ) { checkForTestRoots( module, testFolders, processed ); } } private static boolean isUnderTestSources( @Nonnull PsiClass psiClass ) { ProjectRootManager projectRootManager = ProjectRootManager.getInstance( psiClass.getProject() ); VirtualFile file = psiClass.getContainingFile().getVirtualFile(); if ( file == null ) { return false; } return projectRootManager.getFileIndex().isInTestSourceContent( file ); } @Nullable private static PsiClass getCurrentClass( @Nonnull AnActionEvent e ) { @Nullable Project project = PlatformDataKeys.PROJECT.getData( e.getDataContext() ); if ( project == null ) { return null; } @Nullable PsiFile psiFile = LangDataKeys.PSI_FILE.getData( e.getDataContext() ); if ( psiFile == null ) { return null; } @Nullable Editor editor = PlatformDataKeys.EDITOR.getData( e.getDataContext() ); if ( editor == null ) { return null; } PsiElement element = psiFile.findElementAt( editor.getCaretModel().getOffset() ); return PsiTreeUtil.getParentOfType( element, PsiClass.class ); } }