Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Sergey A Volkov committed Jan 20, 2015
0 parents commit 6b80a33
Show file tree
Hide file tree
Showing 5 changed files with 252 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
out
*.jar
47 changes: 47 additions & 0 deletions META-INF/plugin.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<idea-plugin version="2">
<id>com.yourcompany.unique.plugin.id</id>
<name>Plugin display name here</name>
<version>1.0</version>
<vendor email="[email protected]" url="http://www.yourcompany.com">YourCompany</vendor>

<description><![CDATA[
Enter short description for your plugin here.<br>
<em>most HTML tags may be used</em>
]]></description>

<change-notes><![CDATA[
Add change notes here.<br>
<em>most HTML tags may be used</em>
]]>
</change-notes>

<!-- please see http://confluence.jetbrains.com/display/IDEADEV/Build+Number+Ranges for description -->
<idea-version since-build="131"/>

<!-- please see http://confluence.jetbrains.com/display/IDEADEV/Plugin+Compatibility+with+IntelliJ+Platform+Products
on how to target different products -->
<!-- uncomment to enable plugin in all products
<depends>com.intellij.modules.lang</depends>
-->

<extensions defaultExtensionNs="com.intellij">
<!-- Add your extensions here -->
</extensions>

<application-components>
<!-- Add your application components here -->
</application-components>

<project-components>
<!-- Add your project components here -->
</project-components>

<actions>
<!-- Add your actions here -->
<action id="jsoncreator.jsoncreator" class="ru.volkov.idea.jsoncreator.JsonCreatorAction" text="JsonCreator" description="creates json">
<add-to-group group-id="GenerateGroup" anchor="last"/>
<keyboard-shortcut keymap="$default" first-keystroke="shift alt J" second-keystroke="shift alt K"/>
</action>
</actions>

</idea-plugin>
12 changes: 12 additions & 0 deletions jsoncreator.iml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PLUGIN_MODULE" version="4">
<component name="DevKit.ModuleBuildProperties" url="file://$MODULE_DIR$/META-INF/plugin.xml" />
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
23 changes: 23 additions & 0 deletions src/ru/volkov/idea/jsoncreator/JsonCreatorAction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package ru.volkov.idea.jsoncreator;

import com.intellij.codeInsight.generation.actions.BaseGenerateAction;
import com.intellij.psi.PsiAnonymousClass;
import com.intellij.psi.PsiClass;

/**
* User: serg-v
* Date: 12/15/14
* Time: 3:07 AM
*/
public class JsonCreatorAction extends BaseGenerateAction {

public JsonCreatorAction() {
super(new JsonCreatorHandler());
}

@Override
protected boolean isValidForClass(final PsiClass targetClass) {
return super.isValidForClass(targetClass) && !(targetClass instanceof PsiAnonymousClass);
}

}
168 changes: 168 additions & 0 deletions src/ru/volkov/idea/jsoncreator/JsonCreatorHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
package ru.volkov.idea.jsoncreator;

import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


import com.intellij.codeInsight.NullableNotNullManager;
import com.intellij.codeInsight.generation.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.codeStyle.VariableKind;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.IncorrectOperationException;

/**
* User: serg-v
* Date: 12/15/14
* Time: 3:12 AM
*/
public class JsonCreatorHandler extends GenerateConstructorHandler {

private static final Logger LOG = Logger.getInstance("#ru.volkov.idea.jsoncreator.JsonCreatorHandler");

@Override
@NotNull
protected List<? extends GenerationInfo> generateMemberPrototypes(PsiClass aClass, ClassMember[] members) throws
IncorrectOperationException
{
List<PsiMethod> baseConstructors = new ArrayList<PsiMethod>();
List<PsiField> fieldsVector = new ArrayList<PsiField>();
for (ClassMember member1 : members) {
PsiElement member = ((PsiElementClassMember) member1).getElement();
if (member instanceof PsiMethod) {
baseConstructors.add((PsiMethod) member);
} else {
fieldsVector.add((PsiField) member);
}
}
PsiField[] fields = fieldsVector.toArray(new PsiField[fieldsVector.size()]);

if (!baseConstructors.isEmpty()) {
List<GenerationInfo> constructors = new ArrayList<GenerationInfo>(baseConstructors.size());
final PsiClass superClass = aClass.getSuperClass();
assert superClass != null;
PsiSubstitutor substitutor = TypeConversionUtil.getSuperClassSubstitutor(superClass, aClass, PsiSubstitutor.EMPTY);
for (PsiMethod baseConstructor : baseConstructors) {
baseConstructor = GenerateMembersUtil.substituteGenericMethod(baseConstructor, substitutor, aClass);
constructors.add(new PsiGenerationInfo(generateConstructorPrototype(aClass, baseConstructor, false, fields)));
}
return filterOutAlreadyInsertedConstructors(aClass, constructors);
}
final List<GenerationInfo> constructors =
Collections.<GenerationInfo>singletonList(new PsiGenerationInfo(generateConstructorPrototype(aClass, null, false, fields)));
return filterOutAlreadyInsertedConstructors(aClass, constructors);
}

private static List<? extends GenerationInfo> filterOutAlreadyInsertedConstructors(PsiClass aClass,
List<? extends GenerationInfo> constructors)
{
boolean alreadyExist = true;
for (GenerationInfo constructor : constructors) {
alreadyExist &= aClass.findMethodBySignature((PsiMethod) constructor.getPsiMember(), false) != null;
}
if (alreadyExist) {
return Collections.emptyList();
}
return constructors;
}

public static PsiMethod generateConstructorPrototype(PsiClass aClass, PsiMethod baseConstructor, boolean copyJavaDoc,
PsiField[] fields) throws
IncorrectOperationException
{
PsiManager manager = aClass.getManager();
JVMElementFactory factory = JVMElementFactories.requireFactory(aClass.getLanguage(), aClass.getProject());
CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(manager.getProject());


PsiMethod constructor = factory.createConstructor(aClass.getName(), aClass);
constructor.getModifierList().addAnnotation("com.fasterxml.jackson.annotation.JsonCreator");

GenerateMembersUtil.setVisibility(aClass, constructor);

if (baseConstructor != null) {
PsiJavaCodeReferenceElement[] throwRefs = baseConstructor.getThrowsList().getReferenceElements();
for (PsiJavaCodeReferenceElement ref : throwRefs) {
constructor.getThrowsList().add(ref);
}

if (copyJavaDoc) {
final PsiDocComment docComment = ((PsiMethod) baseConstructor.getNavigationElement()).getDocComment();
if (docComment != null) {
constructor.addAfter(docComment, null);
}
}
}

boolean isNotEnum = false;
if (baseConstructor != null) {
PsiClass superClass = aClass.getSuperClass();
LOG.assertTrue(superClass != null);
if (!CommonClassNames.JAVA_LANG_ENUM.equals(superClass.getQualifiedName())) {
isNotEnum = true;
if (baseConstructor instanceof PsiCompiledElement) { // to get some parameter names
PsiClass dummyClass = JVMElementFactories.requireFactory(baseConstructor.getLanguage(), baseConstructor.getProject()).createClass("Dummy");
baseConstructor = (PsiMethod) dummyClass.add(baseConstructor);
}
PsiParameter[] params = baseConstructor.getParameterList().getParameters();
for (PsiParameter param : params) {
PsiParameter newParam = factory.createParameter(param.getName(), param.getType(), aClass);
GenerateMembersUtil.copyOrReplaceModifierList(param, newParam);
constructor.getParameterList().add(newParam);
}
}
}

JavaCodeStyleManager javaStyle = JavaCodeStyleManager.getInstance(aClass.getProject());

final PsiMethod dummyConstructor = factory.createConstructor(aClass.getName());
dummyConstructor.getParameterList().replace(constructor.getParameterList().copy());
List<PsiParameter> fieldParams = new ArrayList<PsiParameter>();
for (PsiField field : fields) {
String fieldName = field.getName();
String name = javaStyle.variableNameToPropertyName(fieldName, VariableKind.FIELD);
String parmName = javaStyle.propertyNameToVariableName(name, VariableKind.PARAMETER);
parmName = javaStyle.suggestUniqueVariableName(parmName, dummyConstructor, true);
PsiParameter parm = factory.createParameter(parmName, field.getType(), aClass);


final PsiAnnotation annotation = parm.getModifierList().addAnnotation("com.fasterxml.jackson.annotation.JsonProperty");
PsiAnnotationSupport support = LanguageAnnotationSupport.INSTANCE.forLanguage(annotation.getLanguage());
annotation.setDeclaredAttributeValue("value", support.createLiteralValue(name, annotation));
final NullableNotNullManager nullableManager = NullableNotNullManager.getInstance(field.getProject());
final PsiAnnotation notNull = nullableManager.copyNotNullAnnotation(field);
if (notNull != null) {
parm.getModifierList().addAfter(notNull, null);
}

constructor.getParameterList().add(parm);
dummyConstructor.getParameterList().add(parm.copy());
fieldParams.add(parm);
}

ConstructorBodyGenerator generator = ConstructorBodyGenerator.INSTANCE.forLanguage(aClass.getLanguage());
if (generator != null) {
@NonNls StringBuilder buffer = new StringBuilder();
generator.start(buffer, constructor.getName(), PsiParameter.EMPTY_ARRAY);
if (isNotEnum) {
generator.generateSuperCallIfNeeded(buffer, baseConstructor.getParameterList().getParameters());
}
generator.generateFieldInitialization(buffer, fields, fieldParams.toArray(new PsiParameter[fieldParams.size()]));
generator.finish(buffer);
PsiMethod stub = factory.createMethodFromText(buffer.toString(), aClass);
constructor.getBody().replace(stub.getBody());
}

constructor = (PsiMethod) codeStyleManager.reformat(constructor);
return constructor;
}

}

0 comments on commit 6b80a33

Please sign in to comment.