Если я просто поместил исходный код в ту же папку, что и класс, приведенный ниже код работал бы хорошо как для кода в classpath, так и в jars
Обратите внимание, что нет никаких оснований для добавления префикса к имени "/", но вы должны найти класс верхнего уровня.
Я прошу прощения за то, что он находится в ядре Java, но я не хотел добавлять какие-либо дополнительные зависимости и хотел быть максимально понятным.
package com.stackoverflow.q53749060;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.util.Arrays;
import java.util.stream.Stream;
import org.junit.Test;
import com.stackoverflow.q53749060.Answer.Result.Found;
import com.stackoverflow.q53749060.Answer.Result.NotFound;
import com.stackoverflow.q53749060.MyTopLevelClass.MyNestedClass;
import com.stackoverflow.q53749060.MyTopLevelClassInAnotherJar.MyNestedClassInAnotherJar;
@SuppressWarnings("javadoc")
public class Answer {
static final String[] EXTENSIONS = { "java", "scala" };
@Test
public void test() {
Arrays.stream(EXTENSIONS)
.flatMap(ext -> toSource(ext, MyTopLevelClass.class, MyNestedClass.class,MyTopLevelClassInAnotherJar.class,MyNestedClassInAnotherJar.class, String.class))
.forEach(System.out::println);
}
public Stream<Result> toSource(final String extension, final Class<?>... classes) {
return Arrays.stream(classes)
.map(clazz -> toSource(extension, clazz));
}
public Result toSource(final String extension, final Class<?> clazz) {
Class<?> topLevelClass = clazz;
while (topLevelClass.getEnclosingClass() != null) {
topLevelClass = topLevelClass.getEnclosingClass();
}
final String name = topLevelClass.getName()
.replaceAll("\\.", "/") + "." + extension;
final Thread currentThread = Thread.currentThread();
final ClassLoader contextClassLoader = currentThread.getContextClassLoader();
if (contextClassLoader.getResource(name) == null) {
return new NotFound(clazz);
}
final String source = toSource(name, contextClassLoader);
return new Found(clazz, name, source);
}
public String toSource(final String name, final ClassLoader contextClassLoader) {
try (final InputStream resourceInputStream = contextClassLoader.getResourceAsStream(name);
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
int length;
byte[] data = new byte[1024];
while ((length = resourceInputStream.read(data, 0, data.length)) != -1) {
byteArrayOutputStream.write(data, 0, length);
}
byteArrayOutputStream.flush();
byte[] byteArray = byteArrayOutputStream.toByteArray();
return new String(byteArray);
} catch (IOException ioe) {
throw new UncheckedIOException("Failed to read source file: " + name, ioe);
}
}
static class Result {
final Class<?> clazz;
Result(Class<?> clazz) {
super();
this.clazz = clazz;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((this.clazz == null) ? 0 : this.clazz.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Result other = (Result) obj;
if (this.clazz == null) {
if (other.clazz != null) {
return false;
}
} else if (!this.clazz.equals(other.clazz)) {
return false;
}
return true;
}
@Override
public String toString() {
return "Result [clazz=" + this.clazz + "]";
}
static class Found extends Result {
final String source;
final String path;
Found(Class<?> clazz, String path, String source) {
super(clazz);
this.path = path;
this.source = source;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((this.source == null) ? 0 : this.source.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Found other = (Found) obj;
if (this.source == null) {
if (other.source != null) {
return false;
}
} else if (!this.source.equals(other.source)) {
return false;
}
return true;
}
@Override
public String toString() {
return "Found [source=" + this.source + ", clazz=" + this.clazz + "]";
}
}
static class NotFound extends Result {
NotFound(Class<?> clazz) {
super(clazz);
}
@Override
public String toString() {
return "NotFound [clazz=" + this.clazz + "]";
}
}
}
}