Skip to content

Commit 2094697

Browse files
committed
Dev: add support of getter&setter
1 parent 1543cd5 commit 2094697

File tree

7 files changed

+259
-33
lines changed

7 files changed

+259
-33
lines changed

compiler/src/main/java/com/readdle/codegen/JavaSwiftProcessor.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,14 @@
2626
import javax.lang.model.util.Elements;
2727
import javax.lang.model.util.Types;
2828
import javax.tools.Diagnostic;
29-
import javax.tools.FileObject;
3029
import javax.tools.StandardLocation;
3130

3231
public class JavaSwiftProcessor extends AbstractProcessor {
3332

33+
interface WritableElement {
34+
void generateCode(SwiftWriter swiftWriter, String javaFullName, String swiftType) throws IOException;
35+
}
36+
3437
public static final String FOLDER = "SwiftGenerated";
3538

3639
private Types typeUtils;
@@ -158,7 +161,7 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
158161

159162
for (SwiftReferenceDescriptor referenceDescriptor: swiftReferences.values()) {
160163

161-
for (SwiftFuncDescriptor function : referenceDescriptor.functions) {
164+
for (WritableElement function : referenceDescriptor.functions) {
162165
messager.printMessage(Diagnostic.Kind.NOTE, function.toString());
163166
}
164167

compiler/src/main/java/com/readdle/codegen/SwiftFuncDescriptor.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import javax.lang.model.element.Modifier;
1313
import javax.lang.model.element.VariableElement;
1414

15-
class SwiftFuncDescriptor {
15+
class SwiftFuncDescriptor implements JavaSwiftProcessor.WritableElement {
1616

1717
String name;
1818

@@ -68,7 +68,8 @@ class SwiftFuncDescriptor {
6868
}
6969
}
7070

71-
void generateCode(SwiftWriter swiftWriter, String javaFullName, String swiftType) throws IOException {
71+
@Override
72+
public void generateCode(SwiftWriter swiftWriter, String javaFullName, String swiftType) throws IOException {
7273
String swiftFuncName = "Java_" + javaFullName.replace("/", "_").replace("$", "_00024") + "_" + name;
7374

7475
swiftWriter.emitEmptyLine();
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package com.readdle.codegen;
2+
3+
import com.readdle.codegen.anotation.SwiftFunc;
4+
5+
import java.io.IOException;
6+
7+
import javax.lang.model.element.ExecutableElement;
8+
import javax.lang.model.element.Modifier;
9+
10+
class SwiftGetterDescriptor implements JavaSwiftProcessor.WritableElement {
11+
12+
private String javaName;
13+
private String swiftName;
14+
15+
private boolean isStatic;
16+
17+
private SwiftEnvironment.Type returnSwiftType;
18+
private boolean isReturnTypeOptional;
19+
20+
private String description;
21+
22+
SwiftGetterDescriptor(ExecutableElement executableElement) {
23+
this.javaName = executableElement.getSimpleName().toString();
24+
this.isStatic = executableElement.getModifiers().contains(Modifier.STATIC);
25+
this.returnSwiftType = SwiftEnvironment.parseJavaType(executableElement.getReturnType().toString());
26+
this.isReturnTypeOptional = JavaSwiftProcessor.isNullable(executableElement);
27+
28+
if (executableElement.getThrownTypes().size() != 0) {
29+
throw new IllegalArgumentException("Getter can't throw");
30+
}
31+
32+
if (executableElement.getParameters().size() != 0) {
33+
throw new IllegalArgumentException("Getter can't has parameters");
34+
}
35+
36+
SwiftFunc swiftFunc = executableElement.getAnnotation(SwiftFunc.class);
37+
if (swiftFunc != null && !swiftFunc.value().isEmpty()) {
38+
this.swiftName = swiftFunc.value();
39+
}
40+
else {
41+
this.swiftName = javaName;
42+
if (swiftName.startsWith("get")) {
43+
swiftName = swiftName.substring(3);
44+
}
45+
char first = Character.toLowerCase(swiftName.charAt(0));
46+
swiftName = first + swiftName.substring(1);
47+
}
48+
}
49+
50+
@Override
51+
public void generateCode(SwiftWriter swiftWriter, String javaFullName, String swiftType) throws IOException {
52+
String swiftFuncName = "Java_" + javaFullName.replace("/", "_").replace("$", "_00024") + "_" + javaName;
53+
54+
swiftWriter.emitEmptyLine();
55+
swiftWriter.emitStatement(String.format("@_silgen_name(\"%s\")", swiftFuncName));
56+
swiftWriter.emit(String.format("public func %s(env: UnsafeMutablePointer<JNIEnv?>, %s", swiftFuncName, isStatic ? "clazz: jclass" : "this: jobject"));
57+
swiftWriter.emit(String.format(")%s {\n", returnSwiftType != null ? " -> jobject?" : ""));
58+
swiftWriter.emitEmptyLine();
59+
60+
if (!isStatic) {
61+
swiftWriter.emitStatement(String.format("let swiftSelf: %s", swiftType));
62+
swiftWriter.emitStatement("do {");
63+
swiftWriter.emitStatement(String.format("swiftSelf = try %s.from(javaObject: this)", swiftType));
64+
swiftWriter.emitStatement("}");
65+
swiftWriter.emitStatement("catch {");
66+
swiftWriter.emitStatement("let errorString = String(reflecting: type(of: error)) + String(describing: error)");
67+
swiftWriter.emitStatement("JNI.api.ThrowNew(JNI.env, SwiftRuntimeErrorClass, errorString)");
68+
swiftWriter.emitStatement(String.format("return%s", returnSwiftType != null ? " nil" : ""));
69+
swiftWriter.emitStatement("}");
70+
}
71+
72+
swiftWriter.emitStatement(String.format("let result = %s.%s", isStatic ? swiftType : "swiftSelf", swiftName));
73+
74+
if (returnSwiftType != null) {
75+
swiftWriter.emitStatement("do {");
76+
if (isReturnTypeOptional) {
77+
swiftWriter.emitStatement("return try result?.javaObject()");
78+
}
79+
else {
80+
swiftWriter.emitStatement("return try result.javaObject()");
81+
}
82+
swiftWriter.emitStatement("}");
83+
swiftWriter.emitStatement("catch {");
84+
swiftWriter.emitStatement("let errorString = String(reflecting: type(of: error)) + String(describing: error)");
85+
swiftWriter.emitStatement("JNI.api.ThrowNew(JNI.env, SwiftRuntimeErrorClass, errorString)");
86+
swiftWriter.emitStatement("return nil");
87+
swiftWriter.emitStatement("}");
88+
}
89+
90+
swiftWriter.emitStatement("}");
91+
92+
swiftWriter.emitEmptyLine();
93+
}
94+
95+
@Override
96+
public String toString() {
97+
return "SwiftGetterDescriptor{" +
98+
"javaName='" + javaName + '\'' +
99+
", swiftName='" + swiftName + '\'' +
100+
", isStatic=" + isStatic +
101+
", returnSwiftType=" + returnSwiftType +
102+
", isReturnTypeOptional=" + isReturnTypeOptional +
103+
", description='" + description + '\'' +
104+
'}';
105+
}
106+
}

compiler/src/main/java/com/readdle/codegen/SwiftReferenceDescriptor.java

Lines changed: 14 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.readdle.codegen;
22

3+
import com.readdle.codegen.anotation.SwiftGetter;
34
import com.readdle.codegen.anotation.SwiftReference;
5+
import com.readdle.codegen.anotation.SwiftSetter;
46

57
import java.io.File;
68
import java.io.IOException;
@@ -29,9 +31,8 @@ class SwiftReferenceDescriptor {
2931
private String javaFullName;
3032
private String simpleTypeName;
3133
private String[] importPackages;
32-
private String pointerBasicTypeSig;
3334

34-
List<SwiftFuncDescriptor> functions = new LinkedList<>();
35+
List<JavaSwiftProcessor.WritableElement> functions = new LinkedList<>();
3536

3637
SwiftReferenceDescriptor(TypeElement classElement, Filer filer) throws IllegalArgumentException {
3738
this.annotatedClassElement = classElement;
@@ -100,24 +101,6 @@ class SwiftReferenceDescriptor {
100101
}
101102
}
102103

103-
if (!hasNativePointer) {
104-
TypeElement typeElement = classElement;
105-
while (typeElement.getSuperclass() != null && !hasNativePointer) {
106-
typeElement = (TypeElement) ((DeclaredType)typeElement.getSuperclass()).asElement();
107-
for (Element element : typeElement.getEnclosedElements()) {
108-
if (element.getKind() == ElementKind.FIELD) {
109-
VariableElement variableElement = (VariableElement) element;
110-
if (variableElement.getSimpleName().toString().equals("nativePointer")
111-
&& variableElement.asType().toString().equals("long")) {
112-
hasNativePointer = true;
113-
pointerBasicTypeSig = classElement.getQualifiedName().toString().replace(".", "/");
114-
break;
115-
}
116-
}
117-
}
118-
}
119-
}
120-
121104
if (!hasNativePointer) {
122105
throw new IllegalArgumentException(String.format("%s doesn't contain nativePointer field", simpleTypeName));
123106
}
@@ -134,7 +117,15 @@ class SwiftReferenceDescriptor {
134117
if (element.getKind() == ElementKind.METHOD) {
135118
ExecutableElement executableElement = (ExecutableElement) element;
136119
if (executableElement.getModifiers().contains(Modifier.NATIVE)) {
137-
functions.add(new SwiftFuncDescriptor(executableElement));
120+
if (executableElement.getAnnotation(SwiftGetter.class) != null) {
121+
functions.add(new SwiftGetterDescriptor(executableElement));
122+
}
123+
else if (executableElement.getAnnotation(SwiftSetter.class) != null) {
124+
functions.add(new SwiftSetterDescriptor(executableElement));
125+
}
126+
else {
127+
functions.add(new SwiftFuncDescriptor(executableElement));
128+
}
138129
}
139130
}
140131
}
@@ -149,13 +140,7 @@ File generateCode() throws IOException {
149140
swiftWriter.emitEmptyLine();
150141

151142
swiftWriter.emitStatement(String.format("fileprivate let javaClass = JNI.GlobalFindClass(\"%s\")!", javaFullName));
152-
if (pointerBasicTypeSig != null) {
153-
swiftWriter.emitStatement(String.format("fileprivate let javaPointerClass = JNI.GlobalFindClass(\"%s\")!", pointerBasicTypeSig));
154-
swiftWriter.emitStatement("fileprivate let javaSwiftPointerFiled = JNI.api.GetFieldID(JNI.env, javaPointerClass, \"nativePointer\", \"J\")");
155-
}
156-
else {
157-
swiftWriter.emitStatement("fileprivate let javaSwiftPointerFiled = JNI.api.GetFieldID(JNI.env, javaClass, \"nativePointer\", \"J\")");
158-
}
143+
swiftWriter.emitStatement("fileprivate let javaSwiftPointerFiled = JNI.api.GetFieldID(JNI.env, javaClass, \"nativePointer\", \"J\")");
159144

160145
swiftWriter.emitStatement(String.format("fileprivate let javaConstructor = try! JNI.getJavaEmptyConstructor(forClass: \"%s\")", javaFullName));
161146

@@ -192,7 +177,7 @@ File generateCode() throws IOException {
192177

193178
swiftWriter.endExtension();
194179

195-
for (SwiftFuncDescriptor function : functions) {
180+
for (JavaSwiftProcessor.WritableElement function : functions) {
196181
function.generateCode(swiftWriter, javaFullName, simpleTypeName);
197182
}
198183

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package com.readdle.codegen;
2+
3+
import com.readdle.codegen.anotation.SwiftFunc;
4+
5+
import java.io.IOException;
6+
7+
import javax.lang.model.element.ExecutableElement;
8+
import javax.lang.model.element.Modifier;
9+
10+
class SwiftSetterDescriptor implements JavaSwiftProcessor.WritableElement {
11+
12+
private String javaName;
13+
private String swiftName;
14+
15+
boolean isStatic;
16+
17+
private String description;
18+
19+
private SwiftParamDescriptor param;
20+
21+
SwiftSetterDescriptor(ExecutableElement executableElement) {
22+
this.javaName = executableElement.getSimpleName().toString();
23+
this.isStatic = executableElement.getModifiers().contains(Modifier.STATIC);
24+
25+
if (executableElement.getThrownTypes().size() != 0) {
26+
throw new IllegalArgumentException("Setter can't throw");
27+
}
28+
29+
if (executableElement.getParameters().size() != 1) {
30+
throw new IllegalArgumentException("Setter should have at least 1 parameter");
31+
}
32+
33+
param = new SwiftParamDescriptor(executableElement.getParameters().get(0));
34+
35+
SwiftFunc swiftFunc = executableElement.getAnnotation(SwiftFunc.class);
36+
if (swiftFunc != null && !swiftFunc.value().isEmpty()) {
37+
this.swiftName = swiftFunc.value();
38+
}
39+
else {
40+
this.swiftName = javaName;
41+
if (swiftName.startsWith("set")) {
42+
swiftName = swiftName.substring(3);
43+
}
44+
char first = Character.toLowerCase(swiftName.charAt(0));
45+
swiftName = first + swiftName.substring(1);
46+
}
47+
}
48+
49+
@Override
50+
public void generateCode(SwiftWriter swiftWriter, String javaFullName, String swiftType) throws IOException {
51+
String swiftFuncName = "Java_" + javaFullName.replace("/", "_").replace("$", "_00024") + "_" + javaName;
52+
53+
swiftWriter.emitEmptyLine();
54+
swiftWriter.emitStatement(String.format("@_silgen_name(\"%s\")", swiftFuncName));
55+
swiftWriter.emit(String.format("public func %s(env: UnsafeMutablePointer<JNIEnv?>, %s", swiftFuncName, isStatic ? "clazz: jclass" : "this: jobject"));
56+
swiftWriter.emit(String.format(", j%s: jobject%s) {\n", param.name, param.isOptional ? "?" : ""));
57+
swiftWriter.emitEmptyLine();
58+
59+
if (!isStatic) {
60+
swiftWriter.emitStatement(String.format("let swiftSelf: %s", swiftType));
61+
}
62+
63+
swiftWriter.emitStatement(String.format("let %s: %s%s", param.name, param.swiftType.swiftType, param.isOptional ? "?" : ""));
64+
65+
swiftWriter.emitStatement("do {");
66+
67+
if (!isStatic) {
68+
swiftWriter.emitStatement(String.format("swiftSelf = try %s.from(javaObject: this)", swiftType));
69+
}
70+
71+
if (param.isOptional) {
72+
swiftWriter.emitStatement(String.format("if let j%1$s = j%1$s {", param.name));
73+
swiftWriter.emitStatement(String.format("%1$s = try %2$s.from(javaObject: j%1$s)", param.name, param.swiftType.swiftConstructorType));
74+
swiftWriter.emitStatement("} else {");
75+
swiftWriter.emitStatement(String.format("%s = nil", param.name));
76+
swiftWriter.emitStatement("}");
77+
}
78+
else {
79+
swiftWriter.emitStatement(String.format("%1$s = try %2$s.from(javaObject: j%1$s)", param.name, param.swiftType.swiftConstructorType));
80+
}
81+
82+
swiftWriter.emitStatement("}");
83+
swiftWriter.emitStatement("catch {");
84+
swiftWriter.emitStatement("let errorString = String(reflecting: type(of: error)) + String(describing: error)");
85+
swiftWriter.emitStatement("JNI.api.ThrowNew(JNI.env, SwiftRuntimeErrorClass, errorString)");
86+
swiftWriter.emitStatement("return");
87+
swiftWriter.emitStatement("}");
88+
89+
swiftWriter.emitStatement(String.format("%s.%s = %s", isStatic ? swiftType : "swiftSelf", swiftName, param.name));
90+
swiftWriter.emitStatement("}");
91+
92+
swiftWriter.emitEmptyLine();
93+
}
94+
95+
@Override
96+
public String toString() {
97+
return "SwiftSetterDescriptor{" +
98+
"javaName='" + javaName + '\'' +
99+
", swiftName='" + swiftName + '\'' +
100+
", isStatic=" + isStatic +
101+
", description='" + description + '\'' +
102+
", param=" + param +
103+
'}';
104+
}
105+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.readdle.codegen.anotation;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.RetentionPolicy;
6+
import java.lang.annotation.Target;
7+
8+
@Target(ElementType.METHOD) @Retention(RetentionPolicy.CLASS)
9+
public @interface SwiftGetter {
10+
11+
String value() default "";
12+
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.readdle.codegen.anotation;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.RetentionPolicy;
6+
import java.lang.annotation.Target;
7+
8+
@Target(ElementType.METHOD) @Retention(RetentionPolicy.CLASS)
9+
public @interface SwiftSetter {
10+
11+
String value() default "";
12+
13+
}

0 commit comments

Comments
 (0)