Skip to content

Commit cadda69

Browse files
author
seal
committed
Commit Project
0 parents  commit cadda69

File tree

5 files changed

+394
-0
lines changed

5 files changed

+394
-0
lines changed

JsonToKotlin.iml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<module type="PLUGIN_MODULE" version="4">
3+
<component name="DevKit.ModuleBuildProperties" url="file://$MODULE_DIR$/resources/META-INF/plugin.xml" />
4+
<component name="NewModuleRootManager" inherit-compiler-output="true">
5+
<exclude-output />
6+
<content url="file://$MODULE_DIR$">
7+
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
8+
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
9+
</content>
10+
<orderEntry type="inheritedJdk" />
11+
<orderEntry type="sourceFolder" forTests="false" />
12+
</component>
13+
</module>

resources/META-INF/plugin.xml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<idea-plugin>
2+
<id>wu.seal.tool.jsontokotlin</id>
3+
<name>JsonToKotlinClass</name>
4+
<version>1.0.1</version>
5+
<vendor email="[email protected]" url="https://www.github.com/wuseal">Seal</vendor>
6+
7+
<description><![CDATA[
8+
An plugin for Kotlin to convert Json String into Kotlin data class code<br>
9+
<em>Kotlin</em>
10+
<em>Json</em>
11+
]]></description>
12+
13+
<change-notes><![CDATA[
14+
Fix keyboard shortcut bugs<br>
15+
]]>
16+
</change-notes>
17+
18+
<!-- please see http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/build_number_ranges.html for description -->
19+
<idea-version since-build="145.0"/>
20+
21+
<!-- please see http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/plugin_compatibility.html
22+
on how to target different products -->
23+
<depends>com.intellij.modules.lang</depends>
24+
25+
<extensions defaultExtensionNs="com.intellij">
26+
<!-- Add your extensions here -->
27+
</extensions>
28+
29+
<actions>
30+
<action id="wu.seal.wu.seal.jsontokotlin.makekotlindata" class="wu.seal.jsontokotlin.MakeKotlinClassAction" text="Convert Json Into Kotlin Class" description="convert a json string data into kotlin data class" >
31+
<add-to-group group-id="GenerateGroup" anchor="last"/>
32+
<keyboard-shortcut keymap="$default" first-keystroke="alt k"/>
33+
</action>
34+
<!--<action id="Myplugin.Dialogs" class="" text="Show _Dialog" description="A test menu item" />-->
35+
</actions>
36+
37+
<application-components>
38+
<component>
39+
<implementation-class>wu.seal.jsontokotlin.TestApplication</implementation-class>
40+
</component>
41+
</application-components>
42+
</idea-plugin>
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
package wu.seal.jsontokotlin;
2+
3+
import com.google.gson.*;
4+
import org.jetbrains.annotations.NotNull;
5+
6+
import java.util.HashSet;
7+
import java.util.Map;
8+
import java.util.Set;
9+
10+
/**
11+
* Created by seal.wu on 2017/8/21.
12+
*/
13+
public class KotlinMaker {
14+
private final static Gson gson = new Gson();
15+
16+
private String className;
17+
private JsonElement inputElement;
18+
19+
private Set<String> toBeAppend = new HashSet<String>();
20+
21+
public KotlinMaker(String className, String inputText) {
22+
this.inputElement = gson.fromJson(inputText, JsonElement.class);
23+
this.className = className;
24+
}
25+
26+
public KotlinMaker(String className, JsonElement jsonElement) {
27+
this.inputElement = jsonElement;
28+
this.className = className;
29+
}
30+
31+
public String makeKotlinData() {
32+
StringBuilder stringBuilder = new StringBuilder();
33+
stringBuilder.append("\n");
34+
35+
JsonElement jsonElement = inputElement;
36+
if (jsonElement.isJsonObject()) {
37+
appClassName(stringBuilder);
38+
appendJsonObject(stringBuilder, (JsonObject) jsonElement);
39+
} else {
40+
throw new IllegalArgumentException("不可能有其它情况");
41+
}
42+
43+
int index = stringBuilder.lastIndexOf(",");
44+
if (index != -1) {
45+
stringBuilder.deleteCharAt(index);
46+
}
47+
stringBuilder.append(")");
48+
for (String append : toBeAppend) {
49+
stringBuilder.append("\n");
50+
stringBuilder.append(append);
51+
}
52+
return stringBuilder.toString();
53+
}
54+
55+
private void appClassName(StringBuilder stringBuilder) {
56+
stringBuilder.append("data class ").append(className).append("(\n");
57+
}
58+
59+
60+
private void appendJsonObject(StringBuilder stringBuilder, JsonObject jsonObject) {
61+
for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
62+
String property = entry.getKey();
63+
JsonElement jsonElementValue = entry.getValue();
64+
String type = "String";
65+
if (jsonElementValue.isJsonArray()) {
66+
type = getArrayType(property, (JsonArray) jsonElementValue);
67+
addProperty(stringBuilder, property, type, null);
68+
} else if (jsonElementValue.isJsonPrimitive()) {
69+
type = getPrimitiveType(jsonElementValue);
70+
addProperty(stringBuilder, property, type, jsonElementValue.getAsString());
71+
} else if (jsonElementValue.isJsonObject()) {
72+
type = getJsonObjectType(property, (JsonObject) jsonElementValue);
73+
addProperty(stringBuilder, property, type, null);
74+
} else if (jsonElementValue.isJsonNull()) {
75+
addProperty(stringBuilder, property, type, null);
76+
}
77+
}
78+
}
79+
80+
@NotNull
81+
private String getJsonObjectType(String property, JsonObject jsonElementValue) {
82+
String type;
83+
type = property.subSequence(0, 1).toString().toUpperCase() + property.subSequence(1, property.length());
84+
toBeAppend.add(new KotlinMaker(type, jsonElementValue).makeKotlinData());
85+
return type;
86+
}
87+
88+
@NotNull
89+
private String getArrayType(String property, JsonArray jsonElementValue) {
90+
String type = "String";
91+
JsonArray jsonArray = jsonElementValue;
92+
JsonElement next = jsonArray.iterator().next();
93+
if (next.isJsonPrimitive()) {
94+
String subType = getPrimitiveType(next);
95+
type = "List" + "<" + subType + ">";
96+
97+
} else if (next.isJsonObject()) {
98+
property = modifyPropertyForArrayObjType(property);
99+
String subType = getJsonObjectType(property, (JsonObject) next);
100+
type = "List" + "<" + subType + ">";
101+
/**
102+
* 处理子类
103+
*/
104+
toBeAppend.add(new KotlinMaker(subType, next).makeKotlinData());
105+
} else if (next.isJsonArray()) {
106+
property = modifyPropertyForArrayObjType(property);
107+
String subType = getArrayType(property, (JsonArray) next);
108+
type = "List" + "<" + subType + ">";
109+
110+
} else if (next.isJsonNull()) {
111+
type = "List" + "<" + "String" + ">";
112+
113+
}
114+
return type;
115+
}
116+
117+
@NotNull
118+
private String modifyPropertyForArrayObjType(String property) {
119+
if (property.endsWith("ies")) {
120+
property = property.substring(0, property.length() - 3).concat("y");
121+
} else if (property.contains("List")) {
122+
int firstLatterAfterListIndex = property.lastIndexOf("List") + 4;
123+
if (property.length() > firstLatterAfterListIndex) {
124+
char c = property.charAt(firstLatterAfterListIndex);
125+
if (c >= 'A' && c <= 'Z') {
126+
String pre = property.substring(0, property.lastIndexOf("List"));
127+
String end = property.substring(firstLatterAfterListIndex, property.length());
128+
property = pre.concat(end);
129+
}
130+
} else if (property.length() == firstLatterAfterListIndex) {
131+
property = property.substring(0, property.lastIndexOf("List"));
132+
}
133+
} else if (property.contains("list")) {
134+
if (property.indexOf("list") == 0) {
135+
String end = property.substring(5);
136+
String pre = (property.charAt(4) + "").toLowerCase();
137+
property = pre.concat(end);
138+
}
139+
} else if (property.endsWith("s")) {
140+
property = property.substring(0, property.length() - 1);
141+
}
142+
143+
return property;
144+
}
145+
146+
private void addProperty(StringBuilder stringBuilder, String property, String type, String value) {
147+
stringBuilder.append("\t\tvar ").append(property).append(": ").append(type).append(",");
148+
if (value != null) {
149+
stringBuilder.append("// ").append(value).append("\n");
150+
} else {
151+
stringBuilder.append("\n");
152+
}
153+
}
154+
155+
@NotNull
156+
private String getPrimitiveType(JsonElement next) {
157+
String subType = "String";
158+
JsonPrimitive asJsonPrimitive = next.getAsJsonPrimitive();
159+
if (asJsonPrimitive.isBoolean()) {
160+
subType = "Boolean";
161+
} else if (asJsonPrimitive.isNumber()) {
162+
if (asJsonPrimitive.getAsString().contains(".")) {
163+
subType = "Double";
164+
} else if (asJsonPrimitive.getAsLong() > Integer.MAX_VALUE) {
165+
subType = "Long";
166+
} else {
167+
subType = "Int";
168+
}
169+
} else if (asJsonPrimitive.isString()) {
170+
subType = "String";
171+
}
172+
return subType;
173+
}
174+
175+
}
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
package wu.seal.jsontokotlin;
2+
3+
import com.google.gson.Gson;
4+
import com.google.gson.JsonElement;
5+
import com.google.gson.JsonObject;
6+
import com.google.gson.JsonSyntaxException;
7+
import com.intellij.openapi.actionSystem.AnAction;
8+
import com.intellij.openapi.actionSystem.AnActionEvent;
9+
import com.intellij.openapi.actionSystem.PlatformDataKeys;
10+
import com.intellij.openapi.application.ApplicationManager;
11+
import com.intellij.openapi.command.CommandProcessor;
12+
import com.intellij.openapi.editor.Caret;
13+
import com.intellij.openapi.editor.Document;
14+
import com.intellij.openapi.editor.Editor;
15+
import com.intellij.openapi.fileEditor.FileDocumentManager;
16+
import com.intellij.openapi.project.Project;
17+
import com.intellij.openapi.ui.InputValidator;
18+
import com.intellij.openapi.ui.Messages;
19+
import com.intellij.openapi.vfs.VirtualFile;
20+
import com.intellij.ui.components.JBScrollPane;
21+
import com.intellij.util.ui.JBDimension;
22+
import org.jetbrains.annotations.NotNull;
23+
24+
import javax.swing.*;
25+
import javax.swing.text.JTextComponent;
26+
import java.awt.*;
27+
28+
/**
29+
* Created by Seal.Wu on 2017/8/18.
30+
*/
31+
public class MakeKotlinClassAction extends AnAction {
32+
// If you register the action from Java code, this constructor is used to set the menu item name
33+
// (optionally, you can specify the menu description and an icon to display next to the menu item).
34+
// You can omit this constructor when registering the action in the plugin.xml file.
35+
public MakeKotlinClassAction() {
36+
// Set the menu item name.
37+
super("MakeKotlinClass");
38+
// Set the menu item name, description and icon.
39+
// super("Text _Boxes","Item description",IconLoader.getIcon("/Mypackage/icon.png"));
40+
}
41+
42+
public void actionPerformed(AnActionEvent event) {
43+
Project project = event.getData(PlatformDataKeys.PROJECT);
44+
final Caret caret = event.getData(PlatformDataKeys.CARET);
45+
final Editor editor = event.getData(PlatformDataKeys.EDITOR_EVEN_IF_INACTIVE);
46+
if (editor == null) {
47+
Messages.showWarningDialog("Please open a file in editor state for insert Kotlin code!", "No Editor File");
48+
return;
49+
}
50+
final String className = Messages.showInputDialog(project, "Please input the Class Name for Insert", "Input ClassName", Messages.getInformationIcon());
51+
if (className == null || className.isEmpty()) {
52+
return;
53+
}
54+
final Messages.InputDialog inputDialog = new Messages.InputDialog(project, "Please input the Json Data", "Input Json"
55+
, Messages.getInformationIcon(), "", new InputValidator() {
56+
private final Gson gson = new Gson();
57+
58+
@Override
59+
public boolean checkInput(String inputString) {
60+
try {
61+
JsonElement jsonElement = gson.fromJson(inputString, JsonObject.class);
62+
return true;
63+
} catch (JsonSyntaxException e) {
64+
return false;
65+
}
66+
}
67+
68+
@Override
69+
public boolean canClose(String inputString) {
70+
return true;
71+
}
72+
}) {
73+
@NotNull
74+
protected JPanel createMessagePanel() {
75+
JPanel messagePanel = new JPanel(new BorderLayout());
76+
if (myMessage != null) {
77+
JComponent textComponent = createTextComponent();
78+
messagePanel.add(textComponent, BorderLayout.NORTH);
79+
}
80+
81+
myField = createTextFieldComponent();
82+
messagePanel.add(createScrollableTextComponent(), BorderLayout.SOUTH);
83+
84+
return messagePanel;
85+
}
86+
87+
@Override
88+
protected JTextComponent createTextFieldComponent() {
89+
JTextArea jTextArea = new JTextArea(15, 100);
90+
jTextArea.setMinimumSize(new JBDimension(800, 500));
91+
jTextArea.setMaximumSize(new JBDimension(1000, 700));
92+
jTextArea.setLineWrap(true);
93+
jTextArea.setWrapStyleWord(true);
94+
jTextArea.setAutoscrolls(true);
95+
return jTextArea;
96+
}
97+
98+
99+
protected JComponent createScrollableTextComponent() {
100+
return new JBScrollPane(myField);
101+
}
102+
};
103+
inputDialog.show();
104+
String jsonString = inputDialog.getInputString();
105+
if (jsonString == null || jsonString.isEmpty()) {
106+
return;
107+
}
108+
final KotlinMaker maker = new KotlinMaker(className, jsonString);
109+
110+
final Document document = editor.getDocument();
111+
final VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(document);
112+
113+
CommandProcessor.getInstance().executeCommand(project, new Runnable() {
114+
@Override
115+
public void run() {
116+
ApplicationManager.getApplication().runWriteAction(new Runnable() {
117+
@Override
118+
public void run() {
119+
120+
int offset = 0;
121+
122+
if (caret != null) {
123+
124+
offset = caret.getOffset();
125+
} else {
126+
offset = document.getTextLength() - 1;
127+
}
128+
document.insertString(offset, maker.makeKotlinData());
129+
130+
}
131+
});
132+
}
133+
}, "insertKotlin", null);
134+
Messages.showMessageDialog(project, "Kotlin Code insert successfully!", "Information", Messages.getInformationIcon());
135+
}
136+
}

0 commit comments

Comments
 (0)