/* * Copyright 2011 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.google.web.bindery.requestfactory.apt; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Set; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.Messager; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import javax.lang.model.util.ElementScanner6; import javax.tools.Diagnostic.Kind; /** * This is a trivial scanner that collects {@code @Expect} declarations on a * type. It does not perform any type-chasing or supertype traversal. The named * method on the {@link Messages} class is invoked with the provided arguments * and the resulting message is emitted to the {@link Messager}. */ @SupportedAnnotationTypes({ "com.google.web.bindery.requestfactory.apt.Expect", "com.google.web.bindery.requestfactory.apt.Expected"}) @SupportedSourceVersion(SourceVersion.RELEASE_6) class ExpectCollector extends AbstractProcessor { class Scanner extends ElementScanner6<Void, Void> { private final Messager messager; public Scanner(Messager messager) { this.messager = messager; } @Override public Void scan(Element e, Void p) { Expect expect = e.getAnnotation(Expect.class); if (expect != null) { addExpect(expect, e); } Expected expected = e.getAnnotation(Expected.class); if (expected != null) { for (Expect v : expected.value()) { addExpect(v, e); } } return super.scan(e, p); } private void addExpect(Expect expect, Element accumulator) { Method toInvoke = null; for (Method m : Messages.class.getDeclaredMethods()) { if (m.getName().equals(expect.method())) { toInvoke = m; break; } } if (toInvoke == null) { throw new RuntimeException("No method named " + expect.method()); } String[] originalArgs = expect.args(); Object[] args = new Object[originalArgs.length]; for (int i = 0, j = args.length; i < j; i++) { // Special case for domainMethodWrongModifier if (boolean.class.equals(toInvoke.getParameterTypes()[i])) { args[i] = Boolean.valueOf(originalArgs[i]); } else { args[i] = originalArgs[i]; } } String message; Throwable ex; try { message = (String) toInvoke.invoke(null, args); if (expect.warning()) { message += Messages.warnSuffix(); } messager.printMessage(expect.warning() ? Kind.WARNING : Kind.ERROR, message, accumulator); return; } catch (IllegalArgumentException e) { ex = e; } catch (IllegalAccessException e) { ex = e; } catch (InvocationTargetException e) { ex = e.getCause(); } throw new RuntimeException("Could not get test message", ex); } } @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { Scanner scanner = new Scanner(processingEnv.getMessager()); scanner.scan(roundEnv.getElementsAnnotatedWith(Expect.class), null); scanner.scan(roundEnv.getElementsAnnotatedWith(Expected.class), null); return false; } }