All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gwt.thirdparty.xapi.dev.source.MethodBuffer Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2013, We The Internet Ltd.
 *
 * All rights reserved.
 *
 * Distributed under a modified BSD License as follow:
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * Redistribution in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution, unless otherwise
 * agreed to in a written document signed by a director of We The Internet Ltd.
 *
 * Neither the name of We The Internet nor the names of its contributors may
 * be used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

package com.google.gwt.thirdparty.xapi.dev.source;

import static com.google.gwt.thirdparty.xapi.source.read.JavaVisitor.MODIFIER_DEFAULT;

import com.google.gwt.thirdparty.xapi.collect.impl.SimpleStack;
import com.google.gwt.thirdparty.xapi.source.read.JavaLexer;
import com.google.gwt.thirdparty.xapi.source.read.JavaModel.IsParameter;
import com.google.gwt.thirdparty.xapi.source.read.JavaVisitor.AnnotationMemberVisitor;
import com.google.gwt.thirdparty.xapi.source.read.JavaVisitor.MethodVisitor;
import com.google.gwt.thirdparty.xapi.source.read.JavaVisitor.ParameterVisitor;
import com.google.gwt.thirdparty.xapi.source.read.JavaVisitor.TypeData;

import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Map.Entry;

public class MethodBuffer extends MemberBuffer implements
    MethodVisitor> {

  protected SourceBuilder          context;
  private boolean                     once;
  private boolean                     useJsni = true;
  private String                      methodName;
  private final LinkedHashSet parameters;
  private final LinkedHashSet exceptions;
  private TypeData                    returnType;
  private int                         tryDepth;

  public MethodBuffer(final SourceBuilder context) {
    this(context, INDENT);
  }

  public MethodBuffer(final SourceBuilder context, final String indent) {
    super(indent);
    this.context = context;
    this.indent = indent + INDENT;
    parameters = new LinkedHashSet();
    exceptions = new LinkedHashSet();
  }

  @Override
  public String toString() {
    final StringBuilder b = new StringBuilder(Character.toString(NEW_LINE));
    if (javaDoc != null && javaDoc.isNotEmpty()) {
      b.append(javaDoc.toString());
    }
    b.append(origIndent);
    if (annotations.size() > 0) {
      for (final String anno : annotations) {
        b.append('@').append(anno).append(NEW_LINE).append(origIndent);
      }
    }
    b.append(Modifier.toString(modifier));
    if ((modifier & MODIFIER_DEFAULT) == MODIFIER_DEFAULT) {
      b.append(" default");
    }
    if (returnType.simpleName.length() > 0) {
      b.append(" ");
    }
    // generics
    if (generics.size() > 0) {
      b.append("<");
      String prefix = "";
      for (final String generic : generics) {
        b.append(prefix);
        b.append(generic);
        prefix = ", ";
      }
      b.append("> ");
    }
    // return type
    b.append(returnType);
    b.append(" ");
    if (methodName.length() > 0) {
      // method name
      b.append(methodName);
    }
    // parameters
    b.append(" (");
    String prefix = "";
    for (final String parameter : parameters) {
      b.append(prefix).append(parameter);
      prefix = ", ";
    }
    b.append(") ");
    if (!exceptions.isEmpty()) {
      b.append("\n" + indent + "  throws ");
      prefix = "";
      for (final String exception : exceptions) {
        b.append(prefix).append(exception);
        prefix = ", ";
      }
    }
    final String suffix;
    if (Modifier.isAbstract(modifier)) {
      prefix = ";\n";
      suffix = "";
    } else if (Modifier.isNative(modifier)) {
      if (useJsni) {
        prefix = "/*-{\n";
        suffix = (once ? NEW_LINE : "") + origIndent + "}-*/;\n";
      } else {
        prefix = ";\n";
        suffix = "";
      }
    } else {
      prefix = "{\n";
      suffix = (once ? NEW_LINE : "") + origIndent + "}\n";
    }
    return b.toString() + prefix + super.toString() + suffix;
  }

  public MethodBuffer addExceptions(final String... exceptions) {
    addTypes(this.exceptions, exceptions);
    return this;
  }

  @Override
  public String addImport(final Class cls) {
    return context.getImports().addImport(cls);
  }

  @Override
  public String addImport(final String cls) {
    final String noPkg = cls.replace(context.getPackage() + ".", "");
    if (noPkg.indexOf('.') == -1) {
      return noPkg;
    }
    return context.getImports().addImport(cls);
  }

  @Override
  public String addImportStatic(final Class cls, final String name) {
    return context.getImports().addStatic(cls, name);
  }

  @Override
  public String addImportStatic(final String cls) {
    return context.getImports().addStatic(cls);
  }

  public MethodBuffer addParameters(final String... parameters) {
    for (final String parameter : parameters) {
      final IsParameter param = JavaLexer.lexParam(parameter);
      this.parameters.add(param.toString());
    }
    return this;
  }

  public MethodBuffer addParameter(final Class type, final String name) {
    final String typeName = addImport(type);
    this.parameters.add(typeName + " " + name);
    return this;
  }

  public MethodBuffer addParameter(final String type, final String name) {
    final String typeName = addImport(type);
    this.parameters.add(typeName + " " + name);
    return this;
  }

  @SuppressWarnings("unchecked")
  public MethodBuffer addParameters(final Entry>... parameters) {
    return addParameters(Arrays.asList(parameters));
  }

  public MethodBuffer addParameters(final Iterable>> parameters) {
    addNamedTypes(this.parameters, parameters);
    return this;
  }

  public MethodBuffer addExceptions(final Class... exceptions) {
    addTypes(this.exceptions, exceptions);
    return this;
  }

  public MethodBuffer setExceptions(final Class... exceptions) {
    this.exceptions.clear();
    addTypes(this.exceptions, exceptions);
    return this;
  }

  public MethodBuffer setExceptions(final String... exceptions) {
    this.exceptions.clear();
    addTypes(this.exceptions, exceptions);
    return this;
  }

  /**
   * Uses {@link JavaLexer} to extract a MethodBuffer definition.
   * 

* This is slower than manually setting method metadata, but it does * automatically import fully qualified class names (if and only if there is * not already an imported type matching imported simple name). * * @param definition * - Any valid java method definition. "public void doSomething()" * @return - A method buffer initialized to whatever the provided text lexes. *

* Report any parsing errors to github.com/WeTheInternet/com.google.gwt.thirdparty.xapi and/or * [email protected] */ public MethodBuffer setDefinition(final String definition) { // JavaMetadata will extract all modifiers for us JavaLexer.visitMethodSignature(this, context, definition, 0); return this; } public MethodBuffer setName(final String name) { methodName = name; return this; } public MethodBuffer setParameters(final String... parameters) { this.parameters.clear(); return addParameters(parameters); } @SuppressWarnings("unchecked") public MethodBuffer setParameters(final Entry>... parameters) { this.parameters.clear(); return addParameters(Arrays.asList(parameters)); } public MethodBuffer setParameters(final Iterable>> parameters) { this.parameters.clear(); return addParameters(parameters); } public MethodBuffer setReturnType(final Class cls) { final String pkgName = cls.getPackage().getName(); if (pkgName.length() == 0) { returnType = new TypeData("", cls.getCanonicalName()); } else { returnType = new TypeData(pkgName, cls.getCanonicalName().replace( pkgName + ".", "")); } return this; } public MethodBuffer setReturnType(final String pkgName, final String enclosedClassName) { returnType = new TypeData(pkgName, enclosedClassName); return this; } public MethodBuffer setReturnType(final String canonicalName) { if ("".equals(canonicalName)) { returnType = new TypeData(""); } else { returnType = JavaLexer.extractType(canonicalName, 0); } return this; } public ClassBuffer createLocalClass(final String classDef) { final ClassBuffer cls = new ClassBuffer(context, indent); cls.setDefinition(classDef, classDef.trim().endsWith("{")); assert cls.privacy == 0 : "A local class cannot be " + Modifier.toString(cls.privacy); addToEnd(cls); setNotIndent(); return cls; } @Override protected void onAppend() { if (once) { once = false; onFirstAppend(); } super.onAppend(); } protected void onFirstAppend() { } /** * @param useJsni * - Whether to encapsulate native methods with /*-{ }-* / * @return */ public MethodBuffer setUseJsni(final boolean useJsni) { this.useJsni = useJsni; modifier = modifier | Modifier.NATIVE; return this; } public final MethodBuffer makeJsni() { setUseJsni(true).makeNative(); return this; } public final MethodBuffer makeNative() { if ((modifier & Modifier.ABSTRACT) > 0) { modifier &= ~Modifier.ABSTRACT;// "Cannot be both native and abstract"; } modifier = modifier | Modifier.NATIVE; return this; } @Override public final MethodBuffer makeAbstract() { return super.makeAbstract(); } /** * Add a return clause; the return keyword and semicolon are optional. *

* If you send "throw someException()", a return will not be added. *

* This allows you to use the returnValue() to optionally throw instead of * return. * * @param name * @return */ public MethodBuffer returnValue(final String name) { return println((name.matches("\\s*(throw|return)\\s.*") ? "" : "return ") + name + (name.endsWith(";") ? "" : ";")); } @Override public ParameterVisitor> visitParameter() { return new ParameterVisitor>() { int modifier; private final SimpleStack annotations = new SimpleStack(); @Override public AnnotationMemberVisitor> visitAnnotation( String annoName, final String annoBody, final SourceBuilder receiver) { annoName = addImport(annoName.startsWith("@") ? annoName.substring(1) : annoName); annotations.add("@" + annoName + (annoBody.length() > 0 ? "(" + annoBody + ")" : "")); return null; } @Override public void visitModifier(final int modifier, final SourceBuilder receiver) { this.modifier |= modifier; } @Override public void visitType(final TypeData type, final String name, final boolean varargs, final SourceBuilder receiver) { if (type.pkgName.length() > 0) { receiver.getImports().addImport(type.getImportName()); } final StringBuilder b = new StringBuilder(); for (final String anno : annotations) { b.append(anno).append(' '); } final String mod = Modifier.toString(modifier); if (mod.length() > 0) { b.append(mod).append(" "); } if (varargs) { b.append(type.getSimpleName().replace("[]", "") + " ... " + name); } else { b.append(type.getSimpleName() + " " + name); } parameters.add(b.toString()); } }; } @Override public void visitException(final String type, final SourceBuilder receiver) { exceptions.add(type); } @Override public AnnotationMemberVisitor> visitAnnotation( final String annoName, final String annoBody, final SourceBuilder receiver) { addAnnotation("@" + annoName + (annoBody.trim().length() > 0 ? "(" + annoBody + ")" : "")); return null; } @Override public void visitModifier(final int modifier, final SourceBuilder receiver) { assert validModification(this.modifier, modifier); setModifier(modifier); } private boolean validModification(final int modifier, final int change) { if ((change & Modifier.ABSTRACT) > 0) { if ((modifier & Modifier.STATIC) > 0) { throw new AssertionError("You cannot make a static method abstract.\n" + this); } if ((modifier & Modifier.FINAL) > 0) { throw new AssertionError("You cannot make a final method abstract.\n" + this); } } if ((modifier & Modifier.ABSTRACT) > 0) { if ((change & Modifier.STATIC) > 0) { throw new AssertionError("You cannot make an abstract method static.\n" + this); } if ((change & Modifier.FINAL) > 0) { throw new AssertionError("You cannot make an abstract method final.\n" + this); } } return true; } @Override public void visitGeneric(String generic, final SourceBuilder receiver) { generic = generic.trim(); if (generic.charAt(0) == '<') { generic = generic.substring(1, generic.length() - 1); } for (final String importable : JavaLexer.findImportsInGeneric(generic)) { final String imported = receiver.getImports().addImport(importable); if (importable.length() != imported.length()) { int len = -1; while (len != generic.length()) { len = generic.length(); generic = generic.replace(importable, imported); } } } generics.add(generic); } @Override public void visitJavadoc(final String javadoc, final SourceBuilder receiver) { } @Override public void visitReturnType(final TypeData returnType, final SourceBuilder receiver) { this.returnType = returnType; if (returnType.pkgName.length() > 0) { receiver.getImports().addImport(returnType.getImportName()); } } @Override public void visitName(final String name, final SourceBuilder receiver) { methodName = name; } public MethodBuffer startTry() { tryDepth++; println("try {"); indent(); return this; } public MethodBuffer startTry(final String withResources) { tryDepth++; println("try (" + withResources + ") {"); indent(); return this; } public MethodBuffer startCatch(final String exceptionType, final String exceptionName) { outdent(); println("} catch (" + exceptionType + " " + exceptionName + ") {"); indent(); return this; } public String startCatch(String exceptionType) { outdent(); final int ind = exceptionType.lastIndexOf(' '); String name; if (ind == -1) { name = "e" + tryDepth; exceptionType = exceptionType + " " + name; } else { name = exceptionType.substring(ind + 1); } println("} catch (" + exceptionType + ") {"); indent(); return name; } public MethodBuffer startFinally() { outdent(); println("} finally {"); indent(); return this; } public MethodBuffer endTry() { outdent(); println("}"); tryDepth--; return this; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy