duke@1: /*
darcy@699: * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
duke@1: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@1: *
duke@1: * This code is free software; you can redistribute it and/or modify it
duke@1: * under the terms of the GNU General Public License version 2 only, as
duke@1: * published by the Free Software Foundation.
duke@1: *
duke@1: * This code is distributed in the hope that it will be useful, but WITHOUT
duke@1: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@1: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@1: * version 2 for more details (a copy is included in the LICENSE file that
duke@1: * accompanied this code).
duke@1: *
duke@1: * You should have received a copy of the GNU General Public License version
duke@1: * 2 along with this work; if not, write to the Free Software Foundation,
duke@1: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@1: *
ohair@554: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ohair@554: * or visit www.oracle.com if you need additional information or have any
ohair@554: * questions.
duke@1: */
duke@1:
duke@1: /*
duke@1: * @test
duke@1: * @bug 6380018 6453386 6457283
duke@1: * @summary Test that the constraints guaranteed by the Filer and maintained
duke@1: * @author Joseph D. Darcy
darcy@1466: * @library /tools/javac/lib
duke@1: * @build TestFilerConstraints
duke@1: * @compile -encoding iso-8859-1 -processor TestFilerConstraints -proc:only TestFilerConstraints.java
duke@1: */
duke@1:
duke@1: import java.util.Set;
duke@1: import javax.annotation.processing.*;
duke@1: import javax.lang.model.SourceVersion;
duke@1: import static javax.lang.model.SourceVersion.*;
duke@1: import javax.lang.model.element.*;
duke@1: import javax.lang.model.util.*;
duke@1: import static javax.lang.model.util.ElementFilter.*;
duke@1: import static javax.tools.Diagnostic.Kind.*;
duke@1: import static javax.tools.StandardLocation.*;
duke@1:
duke@1: import java.io.*;
duke@1: import java.nio.charset.Charset;
duke@1:
duke@1: /**
duke@1: * A processor that verifies the explicit and implicit constraints in
duke@1: * the Filer contract are maintained:
duke@1: *
duke@1: *
duke@1: *
duke@1: * During each run of an annotation processing tool, a file with a
duke@1: * given pathname may be created only once. If that file already
duke@1: * exists before the first attempt to create it, the old contents
duke@1: * will be deleted. Any subsequent attempt to create the same file
duke@1: * during a run will throw a FilerException, as will attempting to
duke@1: * open both a class file and source file for the same type name.
duke@1: *
duke@1: *
duke@1: *
duke@1: * Specific checks will include:
duke@1: *
duke@1: *
duke@1: *
duke@1: * - Source and class files can be written to from either a Writer or an OutputStream.
duke@1: *
duke@1: *
- Calling close multiple times does not re-register the file for
duke@1: * processing.
duke@1: *
duke@1: *
duke@1: */
darcy@699: public class TestFilerConstraints extends JavacTestingAbstractProcessor {
duke@1: private int round = 0;
duke@1:
duke@1: private PrintWriter pw_src1 = null;
duke@1: private PrintWriter pw_src2 = null;
duke@1: private OutputStream os_classFile1 = null;
duke@1: private Writer pw_classFile2 = null;
duke@1:
duke@1: public boolean process(Set extends TypeElement> annotations,
duke@1: RoundEnvironment roundEnv) {
duke@1: round++;
duke@1:
duke@1: try {
duke@1: switch(round) {
duke@1: // Open two source files
duke@1: case 1:
duke@1: pw_src1 = new PrintWriter(filer.createSourceFile("Src1").openWriter());
duke@1: pw_src1.println("class Src1 {}");
duke@1: pw_src1.close();
duke@1:
duke@1: // Hold open across rounds
duke@1: pw_src2 = new PrintWriter(new OutputStreamWriter(filer.createSourceFile("Src2").openOutputStream()));
duke@1: break;
duke@1:
duke@1: case 2:
duke@1: testExpectedType(roundEnv, "Src1");
duke@1:
duke@1: // Close Src1 a second time
duke@1: pw_src1.close();
duke@1:
duke@1: pw_src2.println("class Src2 {}");
duke@1: pw_src2.close();
duke@1:
duke@1: break;
duke@1:
duke@1: case 3:
duke@1: testExpectedType(roundEnv, "Src2");
duke@1:
duke@1: // Close Src2 a second time
duke@1: pw_src2.close();
duke@1:
duke@1: os_classFile1 = filer.createClassFile("ClassFile1").openOutputStream();
duke@1: for (int value : classFile1Bytes)
duke@1: os_classFile1.write((byte)value);
duke@1: os_classFile1.close();
duke@1:
duke@1: break;
duke@1:
duke@1: case 4:
duke@1: testExpectedType(roundEnv, "ClassFile1");
duke@1:
duke@1: // Close a second time
duke@1: os_classFile1.close();
duke@1:
duke@1: testReopening();
duke@1:
duke@1: pw_classFile2 = new PrintWriter(filer.createClassFile("ClassFile2",
duke@1: (Element[])null).openWriter());
duke@1:
duke@1: for(int byteVal : classFile2Bytes) {
duke@1: // int value = (0xff00 & (classFile2Bytes[i]<<8)) | classFile2Bytes[i+1];
duke@1: // System.out.print(Integer.toHexString(value));
duke@1: //if ((i % 4) == 0)
duke@1: // System.out.println();
duke@1: pw_classFile2.write((char) (0xff & byteVal));
duke@1: }
duke@1: pw_classFile2.close();
duke@1:
duke@1: break;
duke@1:
duke@1:
duke@1:
duke@1: case 5:
duke@1: testExpectedType(roundEnv, "ClassFile2");
duke@1: // Close a second time
duke@1: pw_classFile2.close();
duke@1:
duke@1:
duke@1: break;
duke@1:
duke@1: case 6:
duke@1: if (!roundEnv.processingOver() && !roundEnv.errorRaised())
duke@1: throw new RuntimeException("Bad round state: " + roundEnv);
duke@1: break;
duke@1:
duke@1: default:
duke@1: throw new RuntimeException("Unexpected round number!");
duke@1: }
duke@1: } catch (IOException ioe) {
duke@1: throw new RuntimeException(ioe);
duke@1: }
duke@1:
duke@1: return true;
duke@1: }
duke@1:
duke@1: /**
duke@1: * Test that the single expected expected type, name, is the root
duke@1: * element.
duke@1: */
duke@1: private void testExpectedType(RoundEnvironment roundEnv, String name) {
duke@1: if (!roundEnv.getRootElements().isEmpty()) {
duke@1: for(TypeElement type : typesIn(roundEnv.getRootElements())) {
duke@1: if (!name.contentEquals(type.getSimpleName()))
duke@1: throw new RuntimeException("Unexpected type " + type.getSimpleName());
duke@1: }
duke@1: } else
duke@1: throw new RuntimeException("Unexpected empty root elements.");
duke@1: }
duke@1:
duke@1: private void testReopening() throws IOException {
duke@1: String[] names = {"Src1", "Src2", "ClassFile1"};
duke@1: for (String name : names) {
duke@1: try {
duke@1: filer.createSourceFile(name);
duke@1: throw new RuntimeException("Opened a source file for type " + name);
duke@1: } catch (FilerException fe) {;}
duke@1:
duke@1: try {
duke@1: filer.createClassFile(name);
duke@1: throw new RuntimeException("Opened a class file for type " + name);
duke@1: } catch (FilerException fe) {;}
duke@1: }
duke@1:
duke@1: // Try to open a resource over a source file
duke@1: try {
duke@1: filer.createResource(SOURCE_OUTPUT, "", "Src1.java");
duke@1: throw new RuntimeException("Opened a text file over Src1.java!");
duke@1: } catch (FilerException fe) {;}
duke@1:
duke@1: // Try to open a resource over a class file
duke@1: try {
duke@1: filer.createResource(CLASS_OUTPUT, "", "ClassFile1.class");
duke@1: throw new RuntimeException("Opened a text file over Src1.java!");
duke@1: } catch (FilerException fe) {;}
duke@1:
duke@1: }
duke@1:
duke@1: private int[] classFile1Bytes =
duke@1: {202, 254, 186, 190, 0, 0, 0, 50,
duke@1: 0, 13, 10, 0, 3, 0, 10, 7,
duke@1: 0, 11, 7, 0, 12, 1, 0, 6,
duke@1: 60, 105, 110, 105, 116, 62, 1, 0,
duke@1: 3, 40, 41, 86, 1, 0, 4, 67,
duke@1: 111, 100, 101, 1, 0, 15, 76, 105,
duke@1: 110, 101, 78, 117, 109, 98, 101, 114,
duke@1: 84, 97, 98, 108, 101, 1, 0, 10,
duke@1: 83, 111, 117, 114, 99, 101, 70, 105,
duke@1: 108, 101, 1, 0, 15, 67, 108, 97,
duke@1: 115, 115, 70, 105, 108, 101, 49, 46,
duke@1: 106, 97, 118, 97, 12, 0, 4, 0,
duke@1: 5, 1, 0, 10, 67, 108, 97, 115,
duke@1: 115, 70, 105, 108, 101, 49, 1, 0,
duke@1: 16, 106, 97, 118, 97, 47, 108, 97,
duke@1: 110, 103, 47, 79, 98, 106, 101, 99,
duke@1: 116, 0, 33, 0, 2, 0, 3, 0,
duke@1: 0, 0, 0, 0, 1, 0, 1, 0,
duke@1: 4, 0, 5, 0, 1, 0, 6, 0,
duke@1: 0, 0, 29, 0, 1, 0, 1, 0,
duke@1: 0, 0, 5, 42, 183, 0, 1, 177,
duke@1: 0, 0, 0, 1, 0, 7, 0, 0,
duke@1: 0, 6, 0, 1, 0, 0, 0, 1,
duke@1: 0, 1, 0, 8, 0, 0, 0, 2,
duke@1: 0, 9,};
duke@1:
duke@1: private int[] classFile2Bytes =
duke@1: {202, 254, 186, 190, 0, 0, 0, 50,
duke@1: 0, 13, 10, 0, 3, 0, 10, 7,
duke@1: 0, 11, 7, 0, 12, 1, 0, 6,
duke@1: 60, 105, 110, 105, 116, 62, 1, 0,
duke@1: 3, 40, 41, 86, 1, 0, 4, 67,
duke@1: 111, 100, 101, 1, 0, 15, 76, 105,
duke@1: 110, 101, 78, 117, 109, 98, 101, 114,
duke@1: 84, 97, 98, 108, 101, 1, 0, 10,
duke@1: 83, 111, 117, 114, 99, 101, 70, 105,
duke@1: 108, 101, 1, 0, 15, 67, 108, 97,
duke@1: 115, 115, 70, 105, 108, 101, 50, 46,
duke@1: 106, 97, 118, 97, 12, 0, 4, 0,
duke@1: 5, 1, 0, 10, 67, 108, 97, 115,
duke@1: 115, 70, 105, 108, 101, 50, 1, 0,
duke@1: 16, 106, 97, 118, 97, 47, 108, 97,
duke@1: 110, 103, 47, 79, 98, 106, 101, 99,
duke@1: 116, 0, 33, 0, 2, 0, 3, 0,
duke@1: 0, 0, 0, 0, 1, 0, 1, 0,
duke@1: 4, 0, 5, 0, 1, 0, 6, 0,
duke@1: 0, 0, 29, 0, 1, 0, 1, 0,
duke@1: 0, 0, 5, 42, 183, 0, 1, 177,
duke@1: 0, 0, 0, 1, 0, 7, 0, 0,
duke@1: 0, 6, 0, 1, 0, 0, 0, 1,
duke@1: 0, 1, 0, 8, 0, 0, 0, 2,
duke@1: 0, 9,};
duke@1: }