blob: b9cd39a3b5e5aed64aa69595668bf423d8ebd2eb [file] [log] [blame]
/**
* Copyright (c) 2018 TypeFox and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
package org.eclipse.lsp4j.generator;
import com.google.common.base.Objects;
import com.google.common.collect.Iterables;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import org.eclipse.lsp4j.generator.TypeAdapterImpl;
import org.eclipse.xtend.lib.macro.AbstractClassProcessor;
import org.eclipse.xtend.lib.macro.RegisterGlobalsContext;
import org.eclipse.xtend.lib.macro.TransformationContext;
import org.eclipse.xtend.lib.macro.declaration.AnnotationReference;
import org.eclipse.xtend.lib.macro.declaration.ClassDeclaration;
import org.eclipse.xtend.lib.macro.declaration.FieldDeclaration;
import org.eclipse.xtend.lib.macro.declaration.MutableClassDeclaration;
import org.eclipse.xtend.lib.macro.declaration.MutableConstructorDeclaration;
import org.eclipse.xtend.lib.macro.declaration.MutableFieldDeclaration;
import org.eclipse.xtend.lib.macro.declaration.MutableMethodDeclaration;
import org.eclipse.xtend.lib.macro.declaration.MutableTypeParameterDeclaration;
import org.eclipse.xtend.lib.macro.declaration.Type;
import org.eclipse.xtend.lib.macro.declaration.TypeReference;
import org.eclipse.xtend.lib.macro.declaration.Visibility;
import org.eclipse.xtend2.lib.StringConcatenationClient;
import org.eclipse.xtext.xbase.lib.CollectionLiterals;
import org.eclipse.xtext.xbase.lib.Extension;
import org.eclipse.xtext.xbase.lib.Functions.Function1;
import org.eclipse.xtext.xbase.lib.IterableExtensions;
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
import org.eclipse.xtext.xbase.lib.StringExtensions;
@SuppressWarnings("all")
public class TypeAdapterImplProcessor extends AbstractClassProcessor {
@Override
public void doRegisterGlobals(final ClassDeclaration annotatedClass, @Extension final RegisterGlobalsContext context) {
String _qualifiedName = annotatedClass.getQualifiedName();
String _plus = (_qualifiedName + ".Factory");
context.registerClass(_plus);
}
@Override
public void doTransform(final MutableClassDeclaration annotatedClass, @Extension final TransformationContext context) {
final AnnotationReference typeAdapterImplAnnotation = annotatedClass.findAnnotation(context.findTypeGlobally(TypeAdapterImpl.class));
final TypeReference targetType = typeAdapterImplAnnotation.getClassValue("value");
this.generateImpl(annotatedClass, targetType, context);
String _qualifiedName = annotatedClass.getQualifiedName();
String _plus = (_qualifiedName + ".Factory");
this.generateFactory(context.findClass(_plus), annotatedClass, targetType, context);
}
protected MutableClassDeclaration generateImpl(final MutableClassDeclaration impl, final TypeReference targetType, @Extension final TransformationContext context) {
final ArrayList<FieldDeclaration> targetFields = this.getTargetFields(targetType, context);
final Function1<FieldDeclaration, Boolean> _function = (FieldDeclaration it) -> {
return Boolean.valueOf(((!it.getType().isPrimitive()) && (!it.getType().getActualTypeArguments().isEmpty())));
};
Iterable<FieldDeclaration> _filter = IterableExtensions.<FieldDeclaration>filter(targetFields, _function);
for (final FieldDeclaration field : _filter) {
String _upperCase = field.getSimpleName().toUpperCase();
String _plus = (_upperCase + "_TYPE_TOKEN");
final Procedure1<MutableFieldDeclaration> _function_1 = (MutableFieldDeclaration it) -> {
it.setFinal(true);
it.setStatic(true);
it.setType(context.newTypeReference("com.google.gson.reflect.TypeToken", field.getType()));
StringConcatenationClient _client = new StringConcatenationClient() {
@Override
protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) {
_builder.append("new TypeToken<");
TypeReference _type = field.getType();
_builder.append(_type);
_builder.append(">() {}");
}
};
it.setInitializer(_client);
};
impl.addField(_plus, _function_1);
}
impl.setExtendedClass(context.newTypeReference("com.google.gson.TypeAdapter", targetType));
final Procedure1<MutableFieldDeclaration> _function_2 = (MutableFieldDeclaration it) -> {
it.setType(context.newTypeReference("com.google.gson.Gson"));
it.setFinal(true);
};
impl.addField("gson", _function_2);
final Procedure1<MutableConstructorDeclaration> _function_3 = (MutableConstructorDeclaration it) -> {
it.addParameter("gson", context.newTypeReference("com.google.gson.Gson"));
StringConcatenationClient _client = new StringConcatenationClient() {
@Override
protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) {
_builder.append("this.gson = gson;");
_builder.newLine();
}
};
it.setBody(_client);
};
impl.addConstructor(_function_3);
final Procedure1<MutableMethodDeclaration> _function_4 = (MutableMethodDeclaration method) -> {
method.addParameter("in", context.newTypeReference("com.google.gson.stream.JsonReader"));
method.setExceptions(context.newTypeReference(IOException.class));
method.setReturnType(targetType);
StringConcatenationClient _client = new StringConcatenationClient() {
@Override
protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) {
TypeReference _newTypeReference = context.newTypeReference("com.google.gson.stream.JsonToken");
_builder.append(_newTypeReference);
_builder.append(" nextToken = in.peek();");
_builder.newLineIfNotEmpty();
_builder.append("if (nextToken == JsonToken.NULL) {");
_builder.newLine();
_builder.append("\t");
_builder.append("return null;");
_builder.newLine();
_builder.append("}");
_builder.newLine();
_builder.newLine();
_builder.append(targetType);
_builder.append(" result = new ");
_builder.append(targetType);
_builder.append("();");
_builder.newLineIfNotEmpty();
_builder.append("in.beginObject();");
_builder.newLine();
_builder.append("while (in.hasNext()) {");
_builder.newLine();
_builder.append("\t");
_builder.append("String name = in.nextName();");
_builder.newLine();
_builder.append("\t");
_builder.append("switch (name) {");
_builder.newLine();
{
for(final FieldDeclaration field : targetFields) {
_builder.append("\t");
_builder.append("case \"");
String _simpleName = field.getSimpleName();
_builder.append(_simpleName, "\t");
_builder.append("\":");
_builder.newLineIfNotEmpty();
_builder.append("\t");
_builder.append("\t");
_builder.append("result.set");
String _firstUpper = StringExtensions.toFirstUpper(field.getSimpleName());
_builder.append(_firstUpper, "\t\t");
_builder.append("(read");
String _firstUpper_1 = StringExtensions.toFirstUpper(field.getSimpleName());
_builder.append(_firstUpper_1, "\t\t");
_builder.append("(in));");
_builder.newLineIfNotEmpty();
_builder.append("\t");
_builder.append("\t");
_builder.append("break;");
_builder.newLine();
}
}
_builder.append("\t");
_builder.append("default:");
_builder.newLine();
_builder.append("\t\t");
_builder.append("in.skipValue();");
_builder.newLine();
_builder.append("\t");
_builder.append("}");
_builder.newLine();
_builder.append("}");
_builder.newLine();
_builder.append("in.endObject();");
_builder.newLine();
_builder.append("return result;");
_builder.newLine();
}
};
method.setBody(_client);
};
impl.addMethod("read", _function_4);
for (final FieldDeclaration field_1 : targetFields) {
{
String _firstUpper = StringExtensions.toFirstUpper(field_1.getSimpleName());
String _plus_1 = ("read" + _firstUpper);
final MutableMethodDeclaration existingMethod = impl.findDeclaredMethod(_plus_1,
context.newTypeReference("com.google.gson.stream.JsonReader"));
if ((existingMethod == null)) {
String _firstUpper_1 = StringExtensions.toFirstUpper(field_1.getSimpleName());
String _plus_2 = ("read" + _firstUpper_1);
final Procedure1<MutableMethodDeclaration> _function_5 = (MutableMethodDeclaration it) -> {
it.setVisibility(Visibility.PROTECTED);
it.addParameter("in", context.newTypeReference("com.google.gson.stream.JsonReader"));
it.setExceptions(context.newTypeReference(IOException.class));
it.setReturnType(field_1.getType());
boolean _isPrimitive = field_1.getType().isPrimitive();
if (_isPrimitive) {
String _simpleName = field_1.getType().getSimpleName();
if (_simpleName != null) {
switch (_simpleName) {
case "boolean":
StringConcatenationClient _client = new StringConcatenationClient() {
@Override
protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) {
_builder.append("return in.nextBoolean();");
}
};
it.setBody(_client);
break;
case "double":
StringConcatenationClient _client_1 = new StringConcatenationClient() {
@Override
protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) {
_builder.append("return in.nextDouble();");
}
};
it.setBody(_client_1);
break;
case "float":
StringConcatenationClient _client_2 = new StringConcatenationClient() {
@Override
protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) {
_builder.append("return (float) in.nextDouble();");
}
};
it.setBody(_client_2);
break;
case "long":
StringConcatenationClient _client_3 = new StringConcatenationClient() {
@Override
protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) {
_builder.append("return in.nextLong();");
}
};
it.setBody(_client_3);
break;
case "int":
StringConcatenationClient _client_4 = new StringConcatenationClient() {
@Override
protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) {
_builder.append("return in.nextInt();");
}
};
it.setBody(_client_4);
break;
case "short":
case "byte":
case "char":
StringConcatenationClient _client_5 = new StringConcatenationClient() {
@Override
protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) {
_builder.append("return (");
TypeReference _type = field_1.getType();
_builder.append(_type);
_builder.append(") in.nextInt();");
}
};
it.setBody(_client_5);
break;
}
}
} else {
boolean _isEmpty = field_1.getType().getActualTypeArguments().isEmpty();
boolean _not = (!_isEmpty);
if (_not) {
StringConcatenationClient _client_6 = new StringConcatenationClient() {
@Override
protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) {
_builder.append("return gson.fromJson(in, ");
String _upperCase = field_1.getSimpleName().toUpperCase();
_builder.append(_upperCase);
_builder.append("_TYPE_TOKEN.getType());");
}
};
it.setBody(_client_6);
} else {
StringConcatenationClient _client_7 = new StringConcatenationClient() {
@Override
protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) {
_builder.append("return gson.fromJson(in, ");
TypeReference _type = field_1.getType();
_builder.append(_type);
_builder.append(".class);");
}
};
it.setBody(_client_7);
}
}
};
impl.addMethod(_plus_2, _function_5);
}
}
}
final Procedure1<MutableMethodDeclaration> _function_5 = (MutableMethodDeclaration method) -> {
method.addParameter("out", context.newTypeReference("com.google.gson.stream.JsonWriter"));
method.addParameter("value", targetType);
method.setExceptions(context.newTypeReference(IOException.class));
StringConcatenationClient _client = new StringConcatenationClient() {
@Override
protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) {
_builder.append("if (value == null) {");
_builder.newLine();
_builder.append("\t");
_builder.append("out.nullValue();");
_builder.newLine();
_builder.append("\t");
_builder.append("return;");
_builder.newLine();
_builder.append("}");
_builder.newLine();
_builder.newLine();
_builder.append("out.beginObject();");
_builder.newLine();
{
for(final FieldDeclaration field : targetFields) {
_builder.append("out.name(\"");
String _simpleName = field.getSimpleName();
_builder.append(_simpleName);
_builder.append("\");");
_builder.newLineIfNotEmpty();
_builder.append("write");
String _firstUpper = StringExtensions.toFirstUpper(field.getSimpleName());
_builder.append(_firstUpper);
_builder.append("(out, value.get");
String _firstUpper_1 = StringExtensions.toFirstUpper(field.getSimpleName());
_builder.append(_firstUpper_1);
_builder.append("());");
_builder.newLineIfNotEmpty();
}
}
_builder.append("out.endObject();");
_builder.newLine();
}
};
method.setBody(_client);
};
impl.addMethod("write", _function_5);
final Type booleanType = context.findTypeGlobally(Boolean.class);
final Type numberType = context.findTypeGlobally(Number.class);
final Type stringType = context.findTypeGlobally(String.class);
for (final FieldDeclaration field_2 : targetFields) {
{
String _firstUpper = StringExtensions.toFirstUpper(field_2.getSimpleName());
String _plus_1 = ("write" + _firstUpper);
final MutableMethodDeclaration existingMethod = impl.findDeclaredMethod(_plus_1,
context.newTypeReference("com.google.gson.stream.JsonWriter"), field_2.getType());
if ((existingMethod == null)) {
String _firstUpper_1 = StringExtensions.toFirstUpper(field_2.getSimpleName());
String _plus_2 = ("write" + _firstUpper_1);
final Procedure1<MutableMethodDeclaration> _function_6 = (MutableMethodDeclaration it) -> {
it.setVisibility(Visibility.PROTECTED);
it.addParameter("out", context.newTypeReference("com.google.gson.stream.JsonWriter"));
it.addParameter("value", field_2.getType());
it.setExceptions(context.newTypeReference(IOException.class));
if ((((field_2.getType().isPrimitive() || booleanType.isAssignableFrom(field_2.getType().getType())) || numberType.isAssignableFrom(field_2.getType().getType())) || stringType.isAssignableFrom(field_2.getType().getType()))) {
StringConcatenationClient _client = new StringConcatenationClient() {
@Override
protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) {
_builder.append("out.value(value);");
_builder.newLine();
}
};
it.setBody(_client);
} else {
boolean _isEmpty = field_2.getType().getActualTypeArguments().isEmpty();
boolean _not = (!_isEmpty);
if (_not) {
StringConcatenationClient _client_1 = new StringConcatenationClient() {
@Override
protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) {
_builder.append("gson.toJson(value, ");
String _upperCase = field_2.getSimpleName().toUpperCase();
_builder.append(_upperCase);
_builder.append("_TYPE_TOKEN.getType(), out);");
_builder.newLineIfNotEmpty();
}
};
it.setBody(_client_1);
} else {
TypeReference _type = field_2.getType();
TypeReference _newTypeReference = context.newTypeReference(Object.class);
boolean _equals = Objects.equal(_type, _newTypeReference);
if (_equals) {
StringConcatenationClient _client_2 = new StringConcatenationClient() {
@Override
protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) {
_builder.append("if (value == null)");
_builder.newLine();
_builder.append("\t");
_builder.append("out.nullValue();");
_builder.newLine();
_builder.append("else");
_builder.newLine();
_builder.append("\t");
_builder.append("gson.toJson(value, value.getClass(), out);");
_builder.newLine();
}
};
it.setBody(_client_2);
} else {
StringConcatenationClient _client_3 = new StringConcatenationClient() {
@Override
protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) {
_builder.append("gson.toJson(value, ");
TypeReference _type = field_2.getType();
_builder.append(_type);
_builder.append(".class, out);");
_builder.newLineIfNotEmpty();
}
};
it.setBody(_client_3);
}
}
}
};
impl.addMethod(_plus_2, _function_6);
}
}
}
return impl;
}
protected MutableMethodDeclaration generateFactory(final MutableClassDeclaration factory, final MutableClassDeclaration impl, final TypeReference targetType, @Extension final TransformationContext context) {
MutableMethodDeclaration _xblockexpression = null;
{
TypeReference _newTypeReference = context.newTypeReference("com.google.gson.TypeAdapterFactory");
factory.setImplementedInterfaces(Collections.<TypeReference>unmodifiableList(CollectionLiterals.<TypeReference>newArrayList(_newTypeReference)));
final Procedure1<MutableMethodDeclaration> _function = (MutableMethodDeclaration it) -> {
final MutableTypeParameterDeclaration t = it.addTypeParameter("T");
it.addParameter("gson", context.newTypeReference("com.google.gson.Gson"));
it.addParameter("typeToken", context.newTypeReference("com.google.gson.reflect.TypeToken", context.newTypeReference(t)));
it.setReturnType(context.newTypeReference("com.google.gson.TypeAdapter", context.newTypeReference(t)));
StringConcatenationClient _client = new StringConcatenationClient() {
@Override
protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) {
_builder.append("if (!");
_builder.append(targetType);
_builder.append(".class.isAssignableFrom(typeToken.getRawType())) {");
_builder.newLineIfNotEmpty();
_builder.append("\t");
_builder.append("return null;");
_builder.newLine();
_builder.append("}");
_builder.newLine();
_builder.append("return (TypeAdapter<T>) new ");
_builder.append(impl);
_builder.append("(gson);");
_builder.newLineIfNotEmpty();
}
};
it.setBody(_client);
};
_xblockexpression = factory.addMethod("create", _function);
}
return _xblockexpression;
}
private ArrayList<FieldDeclaration> getTargetFields(final TypeReference targetType, @Extension final TransformationContext context) {
final Type objectType = context.newTypeReference(Object.class).getType();
final ArrayList<FieldDeclaration> targetFields = CollectionLiterals.<FieldDeclaration>newArrayList();
TypeReference typeRef = targetType;
while ((!Objects.equal(typeRef.getType(), objectType))) {
{
Type _type = typeRef.getType();
final ClassDeclaration clazz = ((ClassDeclaration) _type);
final Function1<FieldDeclaration, Boolean> _function = (FieldDeclaration it) -> {
boolean _isStatic = it.isStatic();
return Boolean.valueOf((!_isStatic));
};
Iterable<? extends FieldDeclaration> _filter = IterableExtensions.filter(clazz.getDeclaredFields(), _function);
Iterables.<FieldDeclaration>addAll(targetFields, _filter);
typeRef = clazz.getExtendedClass();
}
}
return targetFields;
}
}