blob: a6afba788fcdbb07e2cfccee78ecf9d4431f9402 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.netbeans.modules.java.debugjavac.impl;
import com.sun.tools.classfile.ConstantPoolException;
import com.sun.tools.javac.api.JavacTool;
import com.sun.tools.javap.Context;
import com.sun.tools.javap.JavapTask;
import com.sun.tools.javap.JavapTask.BadArgs;
import com.sun.tools.javap.JavapTask.ClassFileInfo;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.tools.DiagnosticListener;
import javax.tools.ForwardingJavaFileManager;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileManager.Location;
import javax.tools.JavaFileObject;
import javax.tools.JavaFileObject.Kind;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import org.netbeans.modules.java.debugjavac.Decompiler;
import org.openide.util.Exceptions;
/**
*
* @author lahvac
*/
public class JavapDecompilerImpl implements Decompiler {
@Override
public Result decompile(Input input) {
StringWriter errors = new StringWriter();
StringWriter decompiled = new StringWriter();
try {
final Map<String, byte[]> bytecode = compile(input, errors);
if (!bytecode.isEmpty()) {
for (final Entry<String, byte[]> e : bytecode.entrySet()) {
class JavapTaskImpl extends JavapTask {
public Context getContext() {
return context;
}
}
JavapTaskImpl t = new JavapTaskImpl();
List<String> options = new ArrayList<String>();
options.add("-private");
options.add("-verbose");
options.add(e.getKey());
t.handleOptions(options.toArray(new String[0]));
t.getContext().put(PrintWriter.class, new PrintWriter(decompiled));
ClassFileInfo cfi = t.read(new SimpleJavaFileObject(URI.create("mem://mem"), Kind.CLASS) {
@Override public InputStream openInputStream() throws IOException {
return new ByteArrayInputStream(e.getValue());
}
});
t.write(cfi);
}
}
} catch (IOException | ConstantPoolException ex) {
ex.printStackTrace(new PrintWriter(errors));
} catch (BadArgs ex) {
Exceptions.printStackTrace(ex);
}
return new Result(errors.toString(), decompiled.toString(), "text/x-java-bytecode");
}
private static Map<String, byte[]> compile(Input input, final StringWriter errors) throws IOException {
DiagnosticListener<JavaFileObject> errorsListener = Utilities.errorReportingDiagnosticListener(errors);
StandardJavaFileManager sjfm = JavacTool.create().getStandardFileManager(errorsListener, null, null);
final Map<String, ByteArrayOutputStream> class2BAOS = new HashMap<String, ByteArrayOutputStream>();
JavaFileManager jfm = new ForwardingJavaFileManager<JavaFileManager>(sjfm) {
@Override
public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, javax.tools.FileObject sibling) throws IOException {
final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
class2BAOS.put(className, buffer);
return new SimpleJavaFileObject(sibling.toUri(), kind) {
@Override
public OutputStream openOutputStream() throws IOException {
return buffer;
}
};
}
};
JavaFileObject file = Utilities.sourceFileObject(input.source);
JavacTool.create().getTask(null, jfm, errorsListener, /*XXX:*/Utilities.augmentCommandLineParameters(input), null, Arrays.asList(file)).call();
Map<String, byte[]> result = new HashMap<String, byte[]>();
for (Map.Entry<String, ByteArrayOutputStream> e : class2BAOS.entrySet()) {
result.put(e.getKey(), e.getValue().toByteArray());
}
return result;
}
}