/** * 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; } }