1 /*
2  * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 package jdk.test.lib.compiler;
24 
25 import javax.tools.*;
26 import java.io.ByteArrayOutputStream;
27 import java.io.IOException;
28 import java.io.OutputStream;
29 import java.net.URI;
30 import java.util.Arrays;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.stream.Collectors;
34 
35 public class Compiler {
36     final private Map<String,String> input;
37     private List<String> options;
38 
Compiler(Map<String,String> input)39     public Compiler(Map<String,String> input) {
40         this.input = input;
41     }
42 
setRelease(int release)43     public Compiler setRelease(int release) {
44         // Setting the -release option does not work for some reason
45         // so do it the old fashioned way
46         // options = Arrays.asList("-release", String.valueOf(release));
47         String target = String.valueOf(release);
48         options = Arrays.asList("-source", target, "-target", target, "-classpath", "");
49         return this;
50     }
51 
compile()52     public Map<String,byte[]> compile() {
53         List<SourceFileObject> cunits = createCompilationUnits();
54         Map<String,ClassFileObject> cfos = createClassFileObjects();
55         JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
56         JavaFileManager jfm = new CustomFileManager(jc.getStandardFileManager(null, null, null), cfos);
57         if(!jc.getTask(null, jfm, null, options, null, cunits).call()) {
58             throw new RuntimeException("Compilation failed");
59         }
60         return createOutput(cfos);
61     }
62 
createCompilationUnits()63     private List<SourceFileObject> createCompilationUnits() {
64         return input.entrySet().stream()
65                 .map(e -> new SourceFileObject(e.getKey(), e.getValue())).collect(Collectors.toList());
66     }
67 
createClassFileObjects()68     private Map<String,ClassFileObject> createClassFileObjects() {
69         return input.keySet().stream()
70                 .collect(Collectors.toMap(k -> k, k -> new ClassFileObject(k)));
71     }
72 
createOutput(Map<String,ClassFileObject> cfos)73     private Map<String,byte[]> createOutput(Map<String,ClassFileObject> cfos) {
74         return cfos.keySet().stream().collect(Collectors.toMap(k -> k, k -> cfos.get(k).getBytes()));
75     }
76 
77     private static class SourceFileObject extends SimpleJavaFileObject {
78         private final String source;
79 
SourceFileObject(String name, String source)80         SourceFileObject(String name, String source) {
81             super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
82             this.source = source;
83         }
84 
85         @Override
getCharContent(boolean ignoreEncodingErrors)86         public CharSequence getCharContent(boolean ignoreEncodingErrors) {
87             return source;
88         }
89     }
90 
91     private static class ClassFileObject extends SimpleJavaFileObject {
92         private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
93 
ClassFileObject(String className)94         ClassFileObject(String className) {
95             super(URI.create(className), Kind.CLASS);
96         }
97 
98         @Override
openOutputStream()99         public OutputStream openOutputStream() throws IOException {
100             return baos;
101         }
102 
getBytes()103         public byte[] getBytes() {
104             return baos.toByteArray();
105         }
106     }
107 
108     private static class CustomFileManager extends ForwardingJavaFileManager<JavaFileManager> {
109         private final Map<String,ClassFileObject> cfos;
110 
CustomFileManager(JavaFileManager jfm, Map<String,ClassFileObject> cfos)111         CustomFileManager(JavaFileManager jfm, Map<String,ClassFileObject> cfos) {
112             super(jfm);
113             this.cfos = cfos;
114         }
115 
116         @Override
getJavaFileForOutput(JavaFileManager.Location loc, String name, JavaFileObject.Kind kind, FileObject sibling)117         public JavaFileObject getJavaFileForOutput(JavaFileManager.Location loc, String name,
118                                                    JavaFileObject.Kind kind, FileObject sibling) throws IOException {
119             ClassFileObject cfo = cfos.get(name);
120             return cfo;
121         }
122     }
123 }
124