mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 15:56:48 +08:00
chore: include nb-javac-android as subproject
This commit is contained in:
+119
@@ -0,0 +1,119 @@
|
||||
package com.itsaky.androidide.config;
|
||||
|
||||
import jdkx.lang.model.SourceVersion;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class JavacConfigProvider {
|
||||
|
||||
/**
|
||||
* Property that can be set using <code>System.setProperty</code> to override
|
||||
* the default <code>java.home</code> property in compiler.
|
||||
*/
|
||||
public static String PROP_ANDROIDIDE_JAVA_HOME = "androidide.java.home";
|
||||
|
||||
/**
|
||||
* The latest source version that can be modeled.
|
||||
*/
|
||||
private static SourceVersion latestSourceVersion;
|
||||
|
||||
/**
|
||||
* The latest source version supported by the compiler.
|
||||
*/
|
||||
private static SourceVersion latestSupportedSourceVersion;
|
||||
|
||||
/**
|
||||
* Whether Java 9+ modules are enabled.
|
||||
*/
|
||||
private static boolean modulesEnabled = true;
|
||||
|
||||
static {
|
||||
try {
|
||||
Field latest = tryGetRelease("RELEASE_17");
|
||||
if (latest == null) {
|
||||
latest = tryGetRelease("RELEASE_11");
|
||||
}
|
||||
|
||||
if (latest == null) {
|
||||
latest = tryGetRelease("RELEASE_8");
|
||||
}
|
||||
|
||||
if (latest == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
latestSourceVersion = (SourceVersion)latest.get(null);
|
||||
latestSupportedSourceVersion = latestSourceVersion;
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
static Field tryGetRelease(String release) {
|
||||
try {
|
||||
return SourceVersion.class.getDeclaredField(release);
|
||||
} catch (NoSuchFieldException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the <code>androidide.java.home</code> property if it has been specified
|
||||
* else fallbacks to the <code>java.home</code> property.
|
||||
*/
|
||||
public static String getJavaHome() {
|
||||
String javaHome = System.getProperty(PROP_ANDROIDIDE_JAVA_HOME);
|
||||
if (javaHome == null || javaHome.trim().length() == 0) {
|
||||
javaHome = System.getProperty("java.home");
|
||||
}
|
||||
return javaHome;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether Java 9+ modules are enabled.
|
||||
*/
|
||||
public static boolean isModulesEnabled() {
|
||||
return modulesEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable Java 9+ modules.
|
||||
*/
|
||||
public static void disableModules() {
|
||||
modulesEnabled = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable Java 9+ modules.
|
||||
*/
|
||||
public static void enableModules() {
|
||||
modulesEnabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the latest source version that can be modeled.
|
||||
*/
|
||||
public static SourceVersion getLatestSourceVersion() {
|
||||
return latestSourceVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the latest source version that can be modeled.
|
||||
*/
|
||||
public static void setLatestSourceVersion(SourceVersion newVersion) {
|
||||
latestSourceVersion = newVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the latest source version supported by the compiler.
|
||||
*/
|
||||
public static SourceVersion getLatestSupportedSourceVersion() {
|
||||
return latestSupportedSourceVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the latest source version supported by the compiler.
|
||||
*/
|
||||
public static void setLatestSupportedSourceVersion(SourceVersion newVersion) {
|
||||
latestSupportedSourceVersion = newVersion;
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.itsaky.androidide.zipfs2;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.spi.FileSystemProvider;
|
||||
import java.util.HashMap;
|
||||
|
||||
import javac.internal.jrtfs.JrtFileSystemProvider;
|
||||
|
||||
public class AndroidFsProvider {
|
||||
|
||||
// Can be overridden to provide custom implementation
|
||||
public static AndroidFsProvider INSTANCE = new AndroidFsProvider();
|
||||
|
||||
public FileSystemProvider zipFsProvider() {
|
||||
return new ZipFileSystemProvider();
|
||||
}
|
||||
|
||||
public FileSystem jrtFileSystem () {
|
||||
try {
|
||||
return new JrtFileSystemProvider().newFileSystem(URI.create("jrt:/"), new HashMap<>(0));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException ("Unable to create instance of JRTFileSystem", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+252
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.zipfs2;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.NonWritableChannelException;
|
||||
import java.nio.channels.SeekableByteChannel;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
public class ByteArrayChannel implements SeekableByteChannel {
|
||||
|
||||
private final ReadWriteLock rwlock = new ReentrantReadWriteLock();
|
||||
private byte buf[];
|
||||
|
||||
/*
|
||||
* The current position of this channel.
|
||||
*/
|
||||
private int pos;
|
||||
|
||||
/*
|
||||
* The index that is one greater than the last valid byte in the channel.
|
||||
*/
|
||||
private int last;
|
||||
|
||||
private boolean closed;
|
||||
private boolean readonly;
|
||||
|
||||
/*
|
||||
* Creates a {@code ByteArrayChannel} with size {@code sz}.
|
||||
*/
|
||||
ByteArrayChannel(int sz, boolean readonly) {
|
||||
this.buf = new byte[sz];
|
||||
this.pos = this.last = 0;
|
||||
this.readonly = readonly;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a ByteArrayChannel with its 'pos' at 0 and its 'last' at buf's end.
|
||||
* Note: no defensive copy of the 'buf', used directly.
|
||||
*/
|
||||
ByteArrayChannel(byte[] buf, boolean readonly) {
|
||||
this.buf = buf;
|
||||
this.pos = 0;
|
||||
this.last = buf.length;
|
||||
this.readonly = readonly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen() {
|
||||
return !closed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long position() throws IOException {
|
||||
beginRead();
|
||||
try {
|
||||
ensureOpen();
|
||||
return pos;
|
||||
} finally {
|
||||
endRead();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SeekableByteChannel position(long pos) throws IOException {
|
||||
beginWrite();
|
||||
try {
|
||||
ensureOpen();
|
||||
if (pos < 0 || pos >= Integer.MAX_VALUE)
|
||||
throw new IllegalArgumentException("Illegal position " + pos);
|
||||
this.pos = Math.min((int)pos, last);
|
||||
return this;
|
||||
} finally {
|
||||
endWrite();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(ByteBuffer dst) throws IOException {
|
||||
beginWrite();
|
||||
try {
|
||||
ensureOpen();
|
||||
if (pos == last)
|
||||
return -1;
|
||||
int n = Math.min(dst.remaining(), last - pos);
|
||||
dst.put(buf, pos, n);
|
||||
pos += n;
|
||||
return n;
|
||||
} finally {
|
||||
endWrite();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SeekableByteChannel truncate(long size) throws IOException {
|
||||
if (readonly)
|
||||
throw new NonWritableChannelException();
|
||||
ensureOpen();
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int write(ByteBuffer src) throws IOException {
|
||||
if (readonly)
|
||||
throw new NonWritableChannelException();
|
||||
beginWrite();
|
||||
try {
|
||||
ensureOpen();
|
||||
int n = src.remaining();
|
||||
ensureCapacity(pos + n);
|
||||
src.get(buf, pos, n);
|
||||
pos += n;
|
||||
if (pos > last) {
|
||||
last = pos;
|
||||
}
|
||||
return n;
|
||||
} finally {
|
||||
endWrite();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long size() throws IOException {
|
||||
beginRead();
|
||||
try {
|
||||
ensureOpen();
|
||||
return last;
|
||||
} finally {
|
||||
endRead();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (closed)
|
||||
return;
|
||||
beginWrite();
|
||||
try {
|
||||
closed = true;
|
||||
buf = null;
|
||||
pos = 0;
|
||||
last = 0;
|
||||
} finally {
|
||||
endWrite();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a newly allocated byte array. Its size is the current
|
||||
* size of this channel and the valid contents of the buffer
|
||||
* have been copied into it.
|
||||
*
|
||||
* @return the current contents of this channel, as a byte array.
|
||||
*/
|
||||
public byte[] toByteArray() {
|
||||
beginRead();
|
||||
try {
|
||||
// avoid copy if last == bytes.length?
|
||||
return Arrays.copyOf(buf, last);
|
||||
} finally {
|
||||
endRead();
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureOpen() throws IOException {
|
||||
if (closed)
|
||||
throw new ClosedChannelException();
|
||||
}
|
||||
|
||||
private final void beginWrite() {
|
||||
rwlock.writeLock().lock();
|
||||
}
|
||||
|
||||
private final void endWrite() {
|
||||
rwlock.writeLock().unlock();
|
||||
}
|
||||
|
||||
private final void beginRead() {
|
||||
rwlock.readLock().lock();
|
||||
}
|
||||
|
||||
private final void endRead() {
|
||||
rwlock.readLock().unlock();
|
||||
}
|
||||
|
||||
private void ensureCapacity(int minCapacity) {
|
||||
// overflow-conscious code
|
||||
if (minCapacity - buf.length > 0) {
|
||||
grow(minCapacity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum size of array to allocate.
|
||||
* Some VMs reserve some header words in an array.
|
||||
* Attempts to allocate larger arrays may result in
|
||||
* OutOfMemoryError: Requested array size exceeds VM limit
|
||||
*/
|
||||
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
|
||||
|
||||
/**
|
||||
* Increases the capacity to ensure that it can hold at least the
|
||||
* number of elements specified by the minimum capacity argument.
|
||||
*
|
||||
* @param minCapacity the desired minimum capacity
|
||||
*/
|
||||
private void grow(int minCapacity) {
|
||||
// overflow-conscious code
|
||||
int oldCapacity = buf.length;
|
||||
int newCapacity = oldCapacity << 1;
|
||||
if (newCapacity - minCapacity < 0)
|
||||
newCapacity = minCapacity;
|
||||
if (newCapacity - MAX_ARRAY_SIZE > 0)
|
||||
newCapacity = hugeCapacity(minCapacity);
|
||||
buf = Arrays.copyOf(buf, newCapacity);
|
||||
}
|
||||
|
||||
private static int hugeCapacity(int minCapacity) {
|
||||
if (minCapacity < 0) // overflow
|
||||
throw new OutOfMemoryError();
|
||||
return (minCapacity > MAX_ARRAY_SIZE) ?
|
||||
Integer.MAX_VALUE :
|
||||
MAX_ARRAY_SIZE;
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
|
||||
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
|
||||
*/
|
||||
package com.itsaky.androidide.zipfs2;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author itsaky
|
||||
*/
|
||||
public class Collections2 {
|
||||
|
||||
public static <T> List<T> listOf(T... values) {
|
||||
final List<T> result = new ArrayList<>();
|
||||
if (values == null) {
|
||||
return result;
|
||||
}
|
||||
result.addAll(Arrays.asList(values));
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <T> Set<T> setOf(T... values) {
|
||||
final Set<T> result = new HashSet<>();
|
||||
if (values == null) {
|
||||
return result;
|
||||
}
|
||||
result.addAll(Arrays.asList(values));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.zipfs2;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
public class JarFileSystemProvider extends ZipFileSystemProvider {
|
||||
|
||||
@Override
|
||||
public String getScheme() {
|
||||
return "jar";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Path uriToPath(URI uri) {
|
||||
String scheme = uri.getScheme();
|
||||
if ((scheme == null) || !scheme.equalsIgnoreCase(getScheme())) {
|
||||
throw new IllegalArgumentException("URI scheme is not '" + getScheme() + "'");
|
||||
}
|
||||
try {
|
||||
String uristr = uri.toString();
|
||||
int end = uristr.indexOf("!/");
|
||||
uristr = uristr.substring(4, (end == -1) ? uristr.length() : end);
|
||||
uri = new URI(uristr);
|
||||
return Paths.get(new URI("file", uri.getHost(), uri.getPath(), null))
|
||||
.toAbsolutePath();
|
||||
} catch (URISyntaxException e) {
|
||||
throw new AssertionError(e); //never thrown
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getPath(URI uri) {
|
||||
FileSystem fs = getFileSystem(uri);
|
||||
String path = uri.getFragment();
|
||||
if (path == null) {
|
||||
String uristr = uri.toString();
|
||||
int off = uristr.indexOf("!/");
|
||||
if (off != -1)
|
||||
path = uristr.substring(off + 2);
|
||||
}
|
||||
if (path != null)
|
||||
return fs.getPath(path);
|
||||
throw new IllegalArgumentException("URI: "
|
||||
+ uri
|
||||
+ " does not contain path fragment ex. jar:///c:/foo.zip!/BAR");
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
|
||||
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Interface.java to edit this template
|
||||
*/
|
||||
package com.itsaky.androidide.zipfs2;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author itsaky
|
||||
*/
|
||||
public interface JarPackageProvider {
|
||||
|
||||
/**
|
||||
* Get the package map from the given archive path.
|
||||
* @return The cached package entries. Should return null or empty map to walk the archive file tree instead.
|
||||
* The keys must be <code>openjdk.tools.javac.file.RelativePath.RelativeDirectory</code>
|
||||
*/
|
||||
public Map<? extends Object, Path> getPackages(Path archivePath);
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.zipfs2;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
import java.nio.charset.CoderResult;
|
||||
import java.nio.charset.CodingErrorAction;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.ISO_8859_1;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
/**
|
||||
* Utility class for zipfile name and comment decoding and encoding
|
||||
*
|
||||
* @author Xueming Shen
|
||||
*/
|
||||
public class ZipCoder {
|
||||
|
||||
static class UTF8 extends ZipCoder {
|
||||
UTF8() {
|
||||
super(UTF_8);
|
||||
}
|
||||
|
||||
@Override
|
||||
byte[] getBytes(String s) { // fast pass for ascii
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
if (s.charAt(i) > 0x7f) return super.getBytes(s);
|
||||
}
|
||||
return s.getBytes(ISO_8859_1);
|
||||
}
|
||||
|
||||
@Override
|
||||
String toString(byte[] ba) {
|
||||
for (byte b : ba) {
|
||||
if (b < 0) return super.toString(ba);
|
||||
}
|
||||
return new String(ba, ISO_8859_1);
|
||||
}
|
||||
}
|
||||
|
||||
private static final ZipCoder utf8 = new UTF8();
|
||||
|
||||
public static ZipCoder get(String csn) {
|
||||
Charset cs = Charset.forName(csn);
|
||||
if (cs.name().equals("UTF-8")) {
|
||||
return utf8;
|
||||
}
|
||||
return new ZipCoder(cs);
|
||||
}
|
||||
|
||||
String toString(byte[] ba) {
|
||||
CharsetDecoder cd = decoder().reset();
|
||||
int clen = (int)(ba.length * cd.maxCharsPerByte());
|
||||
char[] ca = new char[clen];
|
||||
if (clen == 0)
|
||||
return new String(ca);
|
||||
ByteBuffer bb = ByteBuffer.wrap(ba, 0, ba.length);
|
||||
CharBuffer cb = CharBuffer.wrap(ca);
|
||||
CoderResult cr = cd.decode(bb, cb, true);
|
||||
if (!cr.isUnderflow())
|
||||
throw new IllegalArgumentException(cr.toString());
|
||||
cr = cd.flush(cb);
|
||||
if (!cr.isUnderflow())
|
||||
throw new IllegalArgumentException(cr.toString());
|
||||
return new String(ca, 0, cb.position());
|
||||
}
|
||||
|
||||
byte[] getBytes(String s) {
|
||||
CharsetEncoder ce = encoder().reset();
|
||||
char[] ca = s.toCharArray();
|
||||
int len = (int)(ca.length * ce.maxBytesPerChar());
|
||||
byte[] ba = new byte[len];
|
||||
if (len == 0)
|
||||
return ba;
|
||||
ByteBuffer bb = ByteBuffer.wrap(ba);
|
||||
CharBuffer cb = CharBuffer.wrap(ca);
|
||||
CoderResult cr = ce.encode(cb, bb, true);
|
||||
if (!cr.isUnderflow())
|
||||
throw new IllegalArgumentException(cr.toString());
|
||||
cr = ce.flush(bb);
|
||||
if (!cr.isUnderflow())
|
||||
throw new IllegalArgumentException(cr.toString());
|
||||
if (bb.position() == ba.length) // defensive copy?
|
||||
return ba;
|
||||
else
|
||||
return Arrays.copyOf(ba, bb.position());
|
||||
}
|
||||
|
||||
boolean isUTF8() {
|
||||
return cs == UTF_8;
|
||||
}
|
||||
|
||||
private Charset cs;
|
||||
|
||||
private ZipCoder(Charset cs) {
|
||||
this.cs = cs;
|
||||
}
|
||||
|
||||
private final ThreadLocal<CharsetDecoder> decTL = new ThreadLocal<>();
|
||||
private final ThreadLocal<CharsetEncoder> encTL = new ThreadLocal<>();
|
||||
|
||||
private CharsetDecoder decoder() {
|
||||
CharsetDecoder dec = decTL.get();
|
||||
if (dec == null) {
|
||||
dec = cs.newDecoder()
|
||||
.onMalformedInput(CodingErrorAction.REPORT)
|
||||
.onUnmappableCharacter(CodingErrorAction.REPORT);
|
||||
decTL.set(dec);
|
||||
}
|
||||
return dec;
|
||||
}
|
||||
|
||||
private CharsetEncoder encoder() {
|
||||
CharsetEncoder enc = encTL.get();
|
||||
if (enc == null) {
|
||||
enc = cs.newEncoder()
|
||||
.onMalformedInput(CodingErrorAction.REPORT)
|
||||
.onUnmappableCharacter(CodingErrorAction.REPORT);
|
||||
encTL.set(enc);
|
||||
}
|
||||
return enc;
|
||||
}
|
||||
}
|
||||
+251
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.zipfs2;
|
||||
|
||||
/**
|
||||
* @author Xueming Shen
|
||||
*/
|
||||
public class ZipConstants {
|
||||
/*
|
||||
* Compression methods
|
||||
*/
|
||||
static final int METHOD_STORED = 0;
|
||||
static final int METHOD_DEFLATED = 8;
|
||||
static final int METHOD_DEFLATED64 = 9;
|
||||
static final int METHOD_BZIP2 = 12;
|
||||
static final int METHOD_LZMA = 14;
|
||||
static final int METHOD_LZ77 = 19;
|
||||
static final int METHOD_AES = 99;
|
||||
|
||||
/*
|
||||
* General purpose bit flag
|
||||
*/
|
||||
static final int FLAG_ENCRYPTED = 0x01;
|
||||
static final int FLAG_DATADESCR = 0x08; // crc, size and csize in dd
|
||||
static final int FLAG_USE_UTF8 = 0x800; // If this bit is set the filename and
|
||||
// comment fields for this file must be
|
||||
// encoded using UTF-8.
|
||||
/*
|
||||
* Header signatures
|
||||
*/
|
||||
static long LOCSIG = 0x04034b50L; // "PK\003\004"
|
||||
static long EXTSIG = 0x08074b50L; // "PK\007\008"
|
||||
static long CENSIG = 0x02014b50L; // "PK\001\002"
|
||||
static long ENDSIG = 0x06054b50L; // "PK\005\006"
|
||||
|
||||
/*
|
||||
* Header sizes in bytes (including signatures)
|
||||
*/
|
||||
static final int LOCHDR = 30; // LOC header size
|
||||
static final int EXTHDR = 16; // EXT header size
|
||||
static final int CENHDR = 46; // CEN header size
|
||||
static final int ENDHDR = 22; // END header size
|
||||
|
||||
/*
|
||||
* Local file (LOC) header field offsets
|
||||
*/
|
||||
static final int LOCVER = 4; // version needed to extract
|
||||
static final int LOCFLG = 6; // general purpose bit flag
|
||||
static final int LOCHOW = 8; // compression method
|
||||
static final int LOCTIM = 10; // modification time
|
||||
static final int LOCCRC = 14; // uncompressed file crc-32 value
|
||||
static final int LOCSIZ = 18; // compressed size
|
||||
static final int LOCLEN = 22; // uncompressed size
|
||||
static final int LOCNAM = 26; // filename length
|
||||
static final int LOCEXT = 28; // extra field length
|
||||
|
||||
/*
|
||||
* Extra local (EXT) header field offsets
|
||||
*/
|
||||
static final int EXTCRC = 4; // uncompressed file crc-32 value
|
||||
static final int EXTSIZ = 8; // compressed size
|
||||
static final int EXTLEN = 12; // uncompressed size
|
||||
|
||||
/*
|
||||
* Central directory (CEN) header field offsets
|
||||
*/
|
||||
static final int CENVEM = 4; // version made by
|
||||
static final int CENVER = 6; // version needed to extract
|
||||
static final int CENFLG = 8; // encrypt, decrypt flags
|
||||
static final int CENHOW = 10; // compression method
|
||||
static final int CENTIM = 12; // modification time
|
||||
static final int CENCRC = 16; // uncompressed file crc-32 value
|
||||
static final int CENSIZ = 20; // compressed size
|
||||
static final int CENLEN = 24; // uncompressed size
|
||||
static final int CENNAM = 28; // filename length
|
||||
static final int CENEXT = 30; // extra field length
|
||||
static final int CENCOM = 32; // comment length
|
||||
static final int CENDSK = 34; // disk number start
|
||||
static final int CENATT = 36; // internal file attributes
|
||||
static final int CENATX = 38; // external file attributes
|
||||
static final int CENOFF = 42; // LOC header offset
|
||||
|
||||
/*
|
||||
* End of central directory (END) header field offsets
|
||||
*/
|
||||
static final int ENDSUB = 8; // number of entries on this disk
|
||||
static final int ENDTOT = 10; // total number of entries
|
||||
static final int ENDSIZ = 12; // central directory size in bytes
|
||||
static final int ENDOFF = 16; // offset of first CEN header
|
||||
static final int ENDCOM = 20; // zip file comment length
|
||||
|
||||
/*
|
||||
* ZIP64 constants
|
||||
*/
|
||||
static final long ZIP64_ENDSIG = 0x06064b50L; // "PK\006\006"
|
||||
static final long ZIP64_LOCSIG = 0x07064b50L; // "PK\006\007"
|
||||
static final int ZIP64_ENDHDR = 56; // ZIP64 end header size
|
||||
static final int ZIP64_LOCHDR = 20; // ZIP64 end loc header size
|
||||
static final int ZIP64_EXTHDR = 24; // EXT header size
|
||||
static final int ZIP64_EXTID = 0x0001; // Extra field Zip64 header ID
|
||||
|
||||
static final int ZIP64_MINVAL32 = 0xFFFF;
|
||||
static final long ZIP64_MINVAL = 0xFFFFFFFFL;
|
||||
|
||||
/*
|
||||
* Zip64 End of central directory (END) header field offsets
|
||||
*/
|
||||
static final int ZIP64_ENDLEN = 4; // size of zip64 end of central dir
|
||||
static final int ZIP64_ENDVEM = 12; // version made by
|
||||
static final int ZIP64_ENDVER = 14; // version needed to extract
|
||||
static final int ZIP64_ENDNMD = 16; // number of this disk
|
||||
static final int ZIP64_ENDDSK = 20; // disk number of start
|
||||
static final int ZIP64_ENDTOD = 24; // total number of entries on this disk
|
||||
static final int ZIP64_ENDTOT = 32; // total number of entries
|
||||
static final int ZIP64_ENDSIZ = 40; // central directory size in bytes
|
||||
static final int ZIP64_ENDOFF = 48; // offset of first CEN header
|
||||
static final int ZIP64_ENDEXT = 56; // zip64 extensible data sector
|
||||
|
||||
/*
|
||||
* Zip64 End of central directory locator field offsets
|
||||
*/
|
||||
static final int ZIP64_LOCDSK = 4; // disk number start
|
||||
static final int ZIP64_LOCOFF = 8; // offset of zip64 end
|
||||
static final int ZIP64_LOCTOT = 16; // total number of disks
|
||||
|
||||
/*
|
||||
* Zip64 Extra local (EXT) header field offsets
|
||||
*/
|
||||
static final int ZIP64_EXTCRC = 4; // uncompressed file crc-32 value
|
||||
static final int ZIP64_EXTSIZ = 8; // compressed size, 8-byte
|
||||
static final int ZIP64_EXTLEN = 16; // uncompressed size, 8-byte
|
||||
|
||||
/*
|
||||
* Extra field header ID
|
||||
*/
|
||||
static final int EXTID_ZIP64 = 0x0001; // ZIP64
|
||||
static final int EXTID_NTFS = 0x000a; // NTFS
|
||||
static final int EXTID_UNIX = 0x000d; // UNIX
|
||||
static final int EXTID_EFS = 0x0017; // Strong Encryption
|
||||
static final int EXTID_EXTT = 0x5455; // Info-ZIP Extended Timestamp
|
||||
|
||||
/*
|
||||
* fields access methods
|
||||
*/
|
||||
///////////////////////////////////////////////////////
|
||||
static final int CH(byte[] b, int n) {
|
||||
return Byte.toUnsignedInt(b[n]);
|
||||
}
|
||||
|
||||
static final int SH(byte[] b, int n) {
|
||||
return Byte.toUnsignedInt(b[n]) | (Byte.toUnsignedInt(b[n + 1]) << 8);
|
||||
}
|
||||
|
||||
static final long LG(byte[] b, int n) {
|
||||
return ((SH(b, n)) | (SH(b, n + 2) << 16)) & 0xffffffffL;
|
||||
}
|
||||
|
||||
static final long LL(byte[] b, int n) {
|
||||
return (LG(b, n)) | (LG(b, n + 4) << 32);
|
||||
}
|
||||
|
||||
static long getSig(byte[] b, int n) { return LG(b, n); }
|
||||
|
||||
private static boolean pkSigAt(byte[] b, int n, int b1, int b2) {
|
||||
return b[n] == 'P' & b[n + 1] == 'K' & b[n + 2] == b1 & b[n + 3] == b2;
|
||||
}
|
||||
|
||||
static boolean cenSigAt(byte[] b, int n) { return pkSigAt(b, n, 1, 2); }
|
||||
static boolean locSigAt(byte[] b, int n) { return pkSigAt(b, n, 3, 4); }
|
||||
static boolean endSigAt(byte[] b, int n) { return pkSigAt(b, n, 5, 6); }
|
||||
static boolean extSigAt(byte[] b, int n) { return pkSigAt(b, n, 7, 8); }
|
||||
static boolean end64SigAt(byte[] b, int n) { return pkSigAt(b, n, 6, 6); }
|
||||
static boolean locator64SigAt(byte[] b, int n) { return pkSigAt(b, n, 6, 7); }
|
||||
|
||||
// local file (LOC) header fields
|
||||
static final long LOCSIG(byte[] b) { return LG(b, 0); } // signature
|
||||
static final int LOCVER(byte[] b) { return SH(b, 4); } // version needed to extract
|
||||
static final int LOCFLG(byte[] b) { return SH(b, 6); } // general purpose bit flags
|
||||
static final int LOCHOW(byte[] b) { return SH(b, 8); } // compression method
|
||||
static final long LOCTIM(byte[] b) { return LG(b, 10);} // modification time
|
||||
static final long LOCCRC(byte[] b) { return LG(b, 14);} // crc of uncompressed data
|
||||
static final long LOCSIZ(byte[] b) { return LG(b, 18);} // compressed data size
|
||||
static final long LOCLEN(byte[] b) { return LG(b, 22);} // uncompressed data size
|
||||
static final int LOCNAM(byte[] b) { return SH(b, 26);} // filename length
|
||||
static final int LOCEXT(byte[] b) { return SH(b, 28);} // extra field length
|
||||
|
||||
// extra local (EXT) header fields
|
||||
static final long EXTCRC(byte[] b) { return LG(b, 4);} // crc of uncompressed data
|
||||
static final long EXTSIZ(byte[] b) { return LG(b, 8);} // compressed size
|
||||
static final long EXTLEN(byte[] b) { return LG(b, 12);} // uncompressed size
|
||||
|
||||
// end of central directory header (END) fields
|
||||
static final int ENDSUB(byte[] b) { return SH(b, 8); } // number of entries on this disk
|
||||
static final int ENDTOT(byte[] b) { return SH(b, 10);} // total number of entries
|
||||
static final long ENDSIZ(byte[] b) { return LG(b, 12);} // central directory size
|
||||
static final long ENDOFF(byte[] b) { return LG(b, 16);} // central directory offset
|
||||
static final int ENDCOM(byte[] b) { return SH(b, 20);} // size of zip file comment
|
||||
static final int ENDCOM(byte[] b, int off) { return SH(b, off + 20);}
|
||||
|
||||
// zip64 end of central directory recoder fields
|
||||
static final long ZIP64_ENDTOD(byte[] b) { return LL(b, 24);} // total number of entries on disk
|
||||
static final long ZIP64_ENDTOT(byte[] b) { return LL(b, 32);} // total number of entries
|
||||
static final long ZIP64_ENDSIZ(byte[] b) { return LL(b, 40);} // central directory size
|
||||
static final long ZIP64_ENDOFF(byte[] b) { return LL(b, 48);} // central directory offset
|
||||
static final long ZIP64_LOCOFF(byte[] b) { return LL(b, 8);} // zip64 end offset
|
||||
|
||||
// central directory header (CEN) fields
|
||||
static final long CENSIG(byte[] b, int pos) { return LG(b, pos + 0); }
|
||||
static final int CENVEM(byte[] b, int pos) { return SH(b, pos + 4); }
|
||||
static final int CENVER(byte[] b, int pos) { return SH(b, pos + 6); }
|
||||
static final int CENFLG(byte[] b, int pos) { return SH(b, pos + 8); }
|
||||
static final int CENHOW(byte[] b, int pos) { return SH(b, pos + 10);}
|
||||
static final long CENTIM(byte[] b, int pos) { return LG(b, pos + 12);}
|
||||
static final long CENCRC(byte[] b, int pos) { return LG(b, pos + 16);}
|
||||
static final long CENSIZ(byte[] b, int pos) { return LG(b, pos + 20);}
|
||||
static final long CENLEN(byte[] b, int pos) { return LG(b, pos + 24);}
|
||||
static final int CENNAM(byte[] b, int pos) { return SH(b, pos + 28);}
|
||||
static final int CENEXT(byte[] b, int pos) { return SH(b, pos + 30);}
|
||||
static final int CENCOM(byte[] b, int pos) { return SH(b, pos + 32);}
|
||||
static final int CENDSK(byte[] b, int pos) { return SH(b, pos + 34);}
|
||||
static final int CENATT(byte[] b, int pos) { return SH(b, pos + 36);}
|
||||
static final long CENATX(byte[] b, int pos) { return LG(b, pos + 38);}
|
||||
static final long CENOFF(byte[] b, int pos) { return LG(b, pos + 42);}
|
||||
|
||||
/* The END header is followed by a variable length comment of size < 64k. */
|
||||
static final long END_MAXLEN = 0xFFFF + ENDHDR;
|
||||
static final int READBLOCKSZ = 128;
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.zipfs2;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.ClosedDirectoryStreamException;
|
||||
import java.nio.file.DirectoryIteratorException;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.NotDirectoryException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Xueming Shen, Rajendra Gutupalli, Jaya Hangal
|
||||
*/
|
||||
public class ZipDirectoryStream implements DirectoryStream<Path> {
|
||||
|
||||
private final ZipFileSystem zipfs;
|
||||
private final ZipPath dir;
|
||||
private final DirectoryStream.Filter<? super Path> filter;
|
||||
private volatile boolean isClosed;
|
||||
private volatile Iterator<Path> itr;
|
||||
|
||||
ZipDirectoryStream(ZipPath dir,
|
||||
DirectoryStream.Filter<? super java.nio.file.Path> filter)
|
||||
throws IOException
|
||||
{
|
||||
this.zipfs = dir.getFileSystem();
|
||||
this.dir = dir;
|
||||
this.filter = filter;
|
||||
// sanity check
|
||||
if (!zipfs.isDirectory(dir.getResolvedPath()))
|
||||
throw new NotDirectoryException(dir.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Iterator<Path> iterator() {
|
||||
if (isClosed)
|
||||
throw new ClosedDirectoryStreamException();
|
||||
if (itr != null)
|
||||
throw new IllegalStateException("Iterator has already been returned");
|
||||
|
||||
try {
|
||||
itr = zipfs.iteratorOf(dir, filter);
|
||||
} catch (IOException e) {
|
||||
throw new DirectoryIteratorException(e);
|
||||
}
|
||||
|
||||
return new Iterator<Path>() {
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
if (isClosed)
|
||||
return false;
|
||||
return itr.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Path next() {
|
||||
if (isClosed)
|
||||
throw new NoSuchElementException();
|
||||
return itr.next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void close() throws IOException {
|
||||
isClosed = true;
|
||||
}
|
||||
}
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.zipfs2;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.attribute.BasicFileAttributeView;
|
||||
import java.nio.file.attribute.FileAttributeView;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Xueming Shen, Rajendra Gutupalli, Jaya Hangal
|
||||
*/
|
||||
public class ZipFileAttributeView implements BasicFileAttributeView {
|
||||
private static enum AttrID {
|
||||
size,
|
||||
creationTime,
|
||||
lastAccessTime,
|
||||
lastModifiedTime,
|
||||
isDirectory,
|
||||
isRegularFile,
|
||||
isSymbolicLink,
|
||||
isOther,
|
||||
fileKey,
|
||||
compressedSize,
|
||||
crc,
|
||||
method
|
||||
};
|
||||
|
||||
private final ZipPath path;
|
||||
private final boolean isZipView;
|
||||
|
||||
private ZipFileAttributeView(ZipPath path, boolean isZipView) {
|
||||
this.path = path;
|
||||
this.isZipView = isZipView;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // Cast to V
|
||||
static <V extends FileAttributeView> V get(ZipPath path, Class<V> type) {
|
||||
if (type == null)
|
||||
throw new NullPointerException();
|
||||
if (type == BasicFileAttributeView.class)
|
||||
return (V)new ZipFileAttributeView(path, false);
|
||||
if (type == ZipFileAttributeView.class)
|
||||
return (V)new ZipFileAttributeView(path, true);
|
||||
return null;
|
||||
}
|
||||
|
||||
static ZipFileAttributeView get(ZipPath path, String type) {
|
||||
if (type == null)
|
||||
throw new NullPointerException();
|
||||
if (type.equals("basic"))
|
||||
return new ZipFileAttributeView(path, false);
|
||||
if (type.equals("zip"))
|
||||
return new ZipFileAttributeView(path, true);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return isZipView ? "zip" : "basic";
|
||||
}
|
||||
|
||||
public ZipFileAttributes readAttributes() throws IOException {
|
||||
return path.getAttributes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimes(FileTime lastModifiedTime,
|
||||
FileTime lastAccessTime,
|
||||
FileTime createTime)
|
||||
throws IOException
|
||||
{
|
||||
path.setTimes(lastModifiedTime, lastAccessTime, createTime);
|
||||
}
|
||||
|
||||
void setAttribute(String attribute, Object value)
|
||||
throws IOException
|
||||
{
|
||||
try {
|
||||
if (AttrID.valueOf(attribute) == AttrID.lastModifiedTime)
|
||||
setTimes((FileTime)value, null, null);
|
||||
if (AttrID.valueOf(attribute) == AttrID.lastAccessTime)
|
||||
setTimes(null, (FileTime)value, null);
|
||||
if (AttrID.valueOf(attribute) == AttrID.creationTime)
|
||||
setTimes(null, null, (FileTime)value);
|
||||
return;
|
||||
} catch (IllegalArgumentException x) {}
|
||||
throw new UnsupportedOperationException("'" + attribute +
|
||||
"' is unknown or read-only attribute");
|
||||
}
|
||||
|
||||
Map<String, Object> readAttributes(String attributes)
|
||||
throws IOException
|
||||
{
|
||||
ZipFileAttributes zfas = readAttributes();
|
||||
LinkedHashMap<String, Object> map = new LinkedHashMap<>();
|
||||
if ("*".equals(attributes)) {
|
||||
for (AttrID id : AttrID.values()) {
|
||||
try {
|
||||
map.put(id.name(), attribute(id, zfas));
|
||||
} catch (IllegalArgumentException x) {}
|
||||
}
|
||||
} else {
|
||||
String[] as = attributes.split(",");
|
||||
for (String a : as) {
|
||||
try {
|
||||
map.put(a, attribute(AttrID.valueOf(a), zfas));
|
||||
} catch (IllegalArgumentException x) {}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
Object attribute(AttrID id, ZipFileAttributes zfas) {
|
||||
switch (id) {
|
||||
case size:
|
||||
return zfas.size();
|
||||
case creationTime:
|
||||
return zfas.creationTime();
|
||||
case lastAccessTime:
|
||||
return zfas.lastAccessTime();
|
||||
case lastModifiedTime:
|
||||
return zfas.lastModifiedTime();
|
||||
case isDirectory:
|
||||
return zfas.isDirectory();
|
||||
case isRegularFile:
|
||||
return zfas.isRegularFile();
|
||||
case isSymbolicLink:
|
||||
return zfas.isSymbolicLink();
|
||||
case isOther:
|
||||
return zfas.isOther();
|
||||
case fileKey:
|
||||
return zfas.fileKey();
|
||||
case compressedSize:
|
||||
if (isZipView)
|
||||
return zfas.compressedSize();
|
||||
break;
|
||||
case crc:
|
||||
if (isZipView)
|
||||
return zfas.crc();
|
||||
break;
|
||||
case method:
|
||||
if (isZipView)
|
||||
return zfas.method();
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.zipfs2;
|
||||
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
|
||||
/**
|
||||
* The attributes of a file stored in a zip file.
|
||||
*
|
||||
* @author Xueming Shen, Rajendra Gutupalli,Jaya Hangal
|
||||
*/
|
||||
public interface ZipFileAttributes extends BasicFileAttributes {
|
||||
public long compressedSize();
|
||||
public long crc();
|
||||
public int method();
|
||||
public byte[] extra();
|
||||
public byte[] comment();
|
||||
public String toString();
|
||||
}
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.zipfs2;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileStore;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.BasicFileAttributeView;
|
||||
import java.nio.file.attribute.FileAttributeView;
|
||||
import java.nio.file.attribute.FileStoreAttributeView;
|
||||
|
||||
/**
|
||||
* @author Xueming Shen, Rajendra Gutupalli, Jaya Hangal
|
||||
*/
|
||||
public class ZipFileStore extends FileStore {
|
||||
|
||||
private final ZipFileSystem zfs;
|
||||
|
||||
ZipFileStore(ZipPath zpath) {
|
||||
this.zfs = zpath.getFileSystem();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return zfs.toString() + "/";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return "zipfs";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return zfs.isReadOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) {
|
||||
return (type == BasicFileAttributeView.class ||
|
||||
type == ZipFileAttributeView.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsFileAttributeView(String name) {
|
||||
return name.equals("basic") || name.equals("zip");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V extends FileStoreAttributeView> V getFileStoreAttributeView(Class<V> type) {
|
||||
if (type == null)
|
||||
throw new NullPointerException();
|
||||
return (V)null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTotalSpace() throws IOException {
|
||||
return new ZipFileStoreAttributes(this).totalSpace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getUsableSpace() throws IOException {
|
||||
return new ZipFileStoreAttributes(this).usableSpace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getUnallocatedSpace() throws IOException {
|
||||
return new ZipFileStoreAttributes(this).unallocatedSpace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(String attribute) throws IOException {
|
||||
if (attribute.equals("totalSpace"))
|
||||
return getTotalSpace();
|
||||
if (attribute.equals("usableSpace"))
|
||||
return getUsableSpace();
|
||||
if (attribute.equals("unallocatedSpace"))
|
||||
return getUnallocatedSpace();
|
||||
throw new UnsupportedOperationException("does not support the given attribute");
|
||||
}
|
||||
|
||||
private static class ZipFileStoreAttributes {
|
||||
final FileStore fstore;
|
||||
final long size;
|
||||
|
||||
public ZipFileStoreAttributes(ZipFileStore fileStore)
|
||||
throws IOException
|
||||
{
|
||||
Path path = FileSystems.getDefault().getPath(fileStore.name());
|
||||
this.size = Files.size(path);
|
||||
this.fstore = Files.getFileStore(path);
|
||||
}
|
||||
|
||||
public long totalSpace() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public long usableSpace() throws IOException {
|
||||
if (!fstore.isReadOnly())
|
||||
return fstore.getUsableSpace();
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long unallocatedSpace() throws IOException {
|
||||
if (!fstore.isReadOnly())
|
||||
return fstore.getUnallocatedSpace();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
+2978
File diff suppressed because it is too large
Load Diff
+319
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.zipfs2;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.channels.AsynchronousFileChannel;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.SeekableByteChannel;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.DirectoryStream.Filter;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.nio.file.attribute.FileAttribute;
|
||||
import java.nio.file.attribute.FileAttributeView;
|
||||
import java.nio.file.spi.FileSystemProvider;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.zip.ZipException;
|
||||
|
||||
/**
|
||||
* @author Xueming Shen, Rajendra Gutupalli, Jaya Hangal
|
||||
*/
|
||||
public class ZipFileSystemProvider extends FileSystemProvider {
|
||||
|
||||
private final Map<Path, ZipFileSystem> filesystems = new HashMap<>();
|
||||
|
||||
public ZipFileSystemProvider() {}
|
||||
|
||||
@Override
|
||||
public String getScheme() {
|
||||
return "jar";
|
||||
}
|
||||
|
||||
protected Path uriToPath(URI uri) {
|
||||
String scheme = uri.getScheme();
|
||||
if ((scheme == null) || !scheme.equalsIgnoreCase(getScheme())) {
|
||||
throw new IllegalArgumentException("URI scheme is not '" + getScheme() + "'");
|
||||
}
|
||||
try {
|
||||
// only support legacy JAR URL syntax jar:{uri}!/{entry} for now
|
||||
String spec = uri.getRawSchemeSpecificPart();
|
||||
int sep = spec.indexOf("!/");
|
||||
if (sep != -1) {
|
||||
spec = spec.substring(0, sep);
|
||||
}
|
||||
return Paths.get(new URI(spec)).toAbsolutePath();
|
||||
} catch (URISyntaxException e) {
|
||||
throw new IllegalArgumentException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean ensureFile(Path path) {
|
||||
try {
|
||||
BasicFileAttributes attrs =
|
||||
Files.readAttributes(path, BasicFileAttributes.class);
|
||||
if (!attrs.isRegularFile())
|
||||
throw new UnsupportedOperationException();
|
||||
return true;
|
||||
} catch (IOException ioe) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected ZipFileSystem createFs(Path path, Map<String, ?> env) throws IOException {
|
||||
return new ZipFileSystem(this, path, env);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileSystem newFileSystem(URI uri, Map<String, ?> env)
|
||||
throws IOException
|
||||
{
|
||||
Path path = uriToPath(uri);
|
||||
synchronized(filesystems) {
|
||||
Path realPath = null;
|
||||
if (ensureFile(path)) {
|
||||
realPath = path.toRealPath();
|
||||
if (filesystems.containsKey(realPath))
|
||||
throw new FileSystemAlreadyExistsException();
|
||||
}
|
||||
ZipFileSystem zipfs;
|
||||
try {
|
||||
zipfs = createFs(path, env);
|
||||
} catch (ZipException ze) {
|
||||
String pname = path.toString();
|
||||
if (pname.endsWith(".zip") || pname.endsWith(".jar"))
|
||||
throw ze;
|
||||
// assume NOT a zip/jar file
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
if (realPath == null) { // newly created
|
||||
realPath = path.toRealPath();
|
||||
}
|
||||
filesystems.put(realPath, zipfs);
|
||||
return zipfs;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileSystem newFileSystem(Path path, Map<String, ?> env)
|
||||
throws IOException
|
||||
{
|
||||
ensureFile(path);
|
||||
try {
|
||||
return createFs(path, env);
|
||||
} catch (ZipException ze) {
|
||||
String pname = path.toString();
|
||||
if (pname.endsWith(".zip") || pname.endsWith(".jar"))
|
||||
throw ze;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getPath(URI uri) {
|
||||
String spec = uri.getSchemeSpecificPart();
|
||||
int sep = spec.indexOf("!/");
|
||||
if (sep == -1)
|
||||
throw new IllegalArgumentException("URI: "
|
||||
+ uri
|
||||
+ " does not contain path info ex. jar:file:/c:/foo.zip!/BAR");
|
||||
return getFileSystem(uri).getPath(spec.substring(sep + 1));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public FileSystem getFileSystem(URI uri) {
|
||||
synchronized (filesystems) {
|
||||
ZipFileSystem zipfs = null;
|
||||
try {
|
||||
zipfs = filesystems.get(uriToPath(uri).toRealPath());
|
||||
} catch (IOException x) {
|
||||
// ignore the ioe from toRealPath(), return FSNFE
|
||||
}
|
||||
if (zipfs == null)
|
||||
throw new FileSystemNotFoundException();
|
||||
return zipfs;
|
||||
}
|
||||
}
|
||||
|
||||
// Checks that the given file is a UnixPath
|
||||
static final ZipPath toZipPath(Path path) {
|
||||
if (path == null)
|
||||
throw new NullPointerException();
|
||||
if (!(path instanceof ZipPath))
|
||||
throw new ProviderMismatchException();
|
||||
return (ZipPath)path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkAccess(Path path, AccessMode... modes) throws IOException {
|
||||
toZipPath(path).checkAccess(modes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copy(Path src, Path target, CopyOption... options)
|
||||
throws IOException
|
||||
{
|
||||
toZipPath(src).copy(toZipPath(target), options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createDirectory(Path path, FileAttribute<?>... attrs)
|
||||
throws IOException
|
||||
{
|
||||
toZipPath(path).createDirectory(attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void delete(Path path) throws IOException {
|
||||
toZipPath(path).delete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V extends FileAttributeView> V
|
||||
getFileAttributeView(Path path, Class<V> type, LinkOption... options)
|
||||
{
|
||||
return ZipFileAttributeView.get(toZipPath(path), type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileStore getFileStore(Path path) throws IOException {
|
||||
return toZipPath(path).getFileStore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHidden(Path path) {
|
||||
return toZipPath(path).isHidden();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameFile(Path path, Path other) throws IOException {
|
||||
return toZipPath(path).isSameFile(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move(Path src, Path target, CopyOption... options)
|
||||
throws IOException
|
||||
{
|
||||
toZipPath(src).move(toZipPath(target), options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousFileChannel newAsynchronousFileChannel(Path path,
|
||||
Set<? extends OpenOption> options,
|
||||
ExecutorService exec,
|
||||
FileAttribute<?>... attrs)
|
||||
throws IOException
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SeekableByteChannel newByteChannel(Path path,
|
||||
Set<? extends OpenOption> options,
|
||||
FileAttribute<?>... attrs)
|
||||
throws IOException
|
||||
{
|
||||
return toZipPath(path).newByteChannel(options, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DirectoryStream<Path> newDirectoryStream(
|
||||
Path path, Filter<? super Path> filter) throws IOException
|
||||
{
|
||||
return toZipPath(path).newDirectoryStream(filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileChannel newFileChannel(Path path,
|
||||
Set<? extends OpenOption> options,
|
||||
FileAttribute<?>... attrs)
|
||||
throws IOException
|
||||
{
|
||||
return toZipPath(path).newFileChannel(options, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream newInputStream(Path path, OpenOption... options)
|
||||
throws IOException
|
||||
{
|
||||
return toZipPath(path).newInputStream(options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream newOutputStream(Path path, OpenOption... options)
|
||||
throws IOException
|
||||
{
|
||||
return toZipPath(path).newOutputStream(options);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked") // Cast to A
|
||||
public <A extends BasicFileAttributes> A
|
||||
readAttributes(Path path, Class<A> type, LinkOption... options)
|
||||
throws IOException
|
||||
{
|
||||
if (type == BasicFileAttributes.class || type == ZipFileAttributes.class)
|
||||
return (A)toZipPath(path).getAttributes();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object>
|
||||
readAttributes(Path path, String attribute, LinkOption... options)
|
||||
throws IOException
|
||||
{
|
||||
return toZipPath(path).readAttributes(attribute, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path readSymbolicLink(Path link) throws IOException {
|
||||
throw new UnsupportedOperationException("Not supported.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(Path path, String attribute,
|
||||
Object value, LinkOption... options)
|
||||
throws IOException
|
||||
{
|
||||
toZipPath(path).setAttribute(attribute, value, options);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
void removeFileSystem(Path zfpath, ZipFileSystem zfs) throws IOException {
|
||||
synchronized (filesystems) {
|
||||
zfpath = zfpath.toRealPath();
|
||||
if (filesystems.get(zfpath) == zfs)
|
||||
filesystems.remove(zfpath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.zipfs2;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.itsaky.androidide.zipfs2.ZipConstants.*;
|
||||
import static com.itsaky.androidide.zipfs2.ZipUtils.dosToJavaTime;
|
||||
import static com.itsaky.androidide.zipfs2.ZipUtils.unixToJavaTime;
|
||||
import static com.itsaky.androidide.zipfs2.ZipUtils.winToJavaTime;
|
||||
|
||||
/**
|
||||
* Print all loc and cen headers of the ZIP file
|
||||
*
|
||||
* @author Xueming Shen
|
||||
*/
|
||||
public class ZipInfo {
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
if (args.length < 1) {
|
||||
print("Usage: java ZipInfo zfname");
|
||||
} else {
|
||||
Map<String, ?> env = Collections.emptyMap();
|
||||
ZipFileSystem zfs = (ZipFileSystem)(new ZipFileSystemProvider()
|
||||
.newFileSystem(Paths.get(args[0]), env));
|
||||
byte[] cen = zfs.cen;
|
||||
if (cen == null) {
|
||||
print("zip file is empty%n");
|
||||
return;
|
||||
}
|
||||
int pos = 0;
|
||||
byte[] buf = new byte[1024];
|
||||
int no = 1;
|
||||
while (pos + CENHDR < cen.length) {
|
||||
print("----------------#%d--------------------%n", no++);
|
||||
printCEN(cen, pos);
|
||||
|
||||
// use size CENHDR as the extra bytes to read, just in case the
|
||||
// loc.extra is bigger than the cen.extra, try to avoid to read
|
||||
// twice
|
||||
long len = LOCHDR + CENNAM(cen, pos) + CENEXT(cen, pos) + CENHDR;
|
||||
if (zfs.readFullyAt(buf, 0, len, locoff(cen, pos)) != len)
|
||||
ZipFileSystem.zerror("read loc header failed");
|
||||
if (LOCEXT(buf) > CENEXT(cen, pos) + CENHDR) {
|
||||
// have to read the second time;
|
||||
len = LOCHDR + LOCNAM(buf) + LOCEXT(buf);
|
||||
if (zfs.readFullyAt(buf, 0, len, locoff(cen, pos)) != len)
|
||||
ZipFileSystem.zerror("read loc header failed");
|
||||
}
|
||||
printLOC(buf);
|
||||
pos += CENHDR + CENNAM(cen, pos) + CENEXT(cen, pos) + CENCOM(cen, pos);
|
||||
}
|
||||
zfs.close();
|
||||
}
|
||||
}
|
||||
|
||||
static void print(String fmt, Object... objs) {
|
||||
System.out.printf(fmt, objs);
|
||||
}
|
||||
|
||||
static void printLOC(byte[] loc) {
|
||||
print("%n");
|
||||
print("[Local File Header]%n");
|
||||
print(" Signature : %#010x%n", LOCSIG(loc));
|
||||
if (LOCSIG(loc) != LOCSIG) {
|
||||
print(" Wrong signature!");
|
||||
return;
|
||||
}
|
||||
print(" Version : %#6x [%d.%d]%n",
|
||||
LOCVER(loc), LOCVER(loc) / 10, LOCVER(loc) % 10);
|
||||
print(" Flag : %#6x%n", LOCFLG(loc));
|
||||
print(" Method : %#6x%n", LOCHOW(loc));
|
||||
print(" LastMTime : %#10x [%tc]%n",
|
||||
LOCTIM(loc), dosToJavaTime(LOCTIM(loc)));
|
||||
print(" CRC : %#10x%n", LOCCRC(loc));
|
||||
print(" CSize : %#10x%n", LOCSIZ(loc));
|
||||
print(" Size : %#10x%n", LOCLEN(loc));
|
||||
print(" NameLength : %#6x [%s]%n",
|
||||
LOCNAM(loc), new String(loc, LOCHDR, LOCNAM(loc)));
|
||||
print(" ExtraLength : %#6x%n", LOCEXT(loc));
|
||||
if (LOCEXT(loc) != 0)
|
||||
printExtra(loc, LOCHDR + LOCNAM(loc), LOCEXT(loc));
|
||||
}
|
||||
|
||||
static void printCEN(byte[] cen, int off) {
|
||||
print("[Central Directory Header]%n");
|
||||
print(" Signature : %#010x%n", CENSIG(cen, off));
|
||||
if (CENSIG(cen, off) != CENSIG) {
|
||||
print(" Wrong signature!");
|
||||
return;
|
||||
}
|
||||
print(" VerMadeby : %#6x [%d, %d.%d]%n",
|
||||
CENVEM(cen, off), (CENVEM(cen, off) >> 8),
|
||||
(CENVEM(cen, off) & 0xff) / 10,
|
||||
(CENVEM(cen, off) & 0xff) % 10);
|
||||
print(" VerExtract : %#6x [%d.%d]%n",
|
||||
CENVER(cen, off), CENVER(cen, off) / 10, CENVER(cen, off) % 10);
|
||||
print(" Flag : %#6x%n", CENFLG(cen, off));
|
||||
print(" Method : %#6x%n", CENHOW(cen, off));
|
||||
print(" LastMTime : %#10x [%tc]%n",
|
||||
CENTIM(cen, off), dosToJavaTime(CENTIM(cen, off)));
|
||||
print(" CRC : %#10x%n", CENCRC(cen, off));
|
||||
print(" CSize : %#10x%n", CENSIZ(cen, off));
|
||||
print(" Size : %#10x%n", CENLEN(cen, off));
|
||||
print(" NameLen : %#6x [%s]%n",
|
||||
CENNAM(cen, off), new String(cen, off + CENHDR, CENNAM(cen, off)));
|
||||
print(" ExtraLen : %#6x%n", CENEXT(cen, off));
|
||||
if (CENEXT(cen, off) != 0)
|
||||
printExtra(cen, off + CENHDR + CENNAM(cen, off), CENEXT(cen, off));
|
||||
print(" CommentLen : %#6x%n", CENCOM(cen, off));
|
||||
print(" DiskStart : %#6x%n", CENDSK(cen, off));
|
||||
print(" Attrs : %#6x%n", CENATT(cen, off));
|
||||
print(" AttrsEx : %#10x%n", CENATX(cen, off));
|
||||
print(" LocOff : %#10x%n", CENOFF(cen, off));
|
||||
|
||||
}
|
||||
|
||||
static long locoff(byte[] cen, int pos) {
|
||||
long locoff = CENOFF(cen, pos);
|
||||
if (locoff == ZIP64_MINVAL) { //ZIP64
|
||||
int off = pos + CENHDR + CENNAM(cen, pos);
|
||||
int end = off + CENEXT(cen, pos);
|
||||
while (off + 4 < end) {
|
||||
int tag = SH(cen, off);
|
||||
int sz = SH(cen, off + 2);
|
||||
if (tag != EXTID_ZIP64) {
|
||||
off += 4 + sz;
|
||||
continue;
|
||||
}
|
||||
off += 4;
|
||||
if (CENLEN(cen, pos) == ZIP64_MINVAL)
|
||||
off += 8;
|
||||
if (CENSIZ(cen, pos) == ZIP64_MINVAL)
|
||||
off += 8;
|
||||
return LL(cen, off);
|
||||
}
|
||||
// should never be here
|
||||
}
|
||||
return locoff;
|
||||
}
|
||||
|
||||
static void printExtra(byte[] extra, int off, int len) {
|
||||
int end = off + len;
|
||||
while (off + 4 <= end) {
|
||||
int tag = SH(extra, off);
|
||||
int sz = SH(extra, off + 2);
|
||||
print(" [tag=0x%04x, sz=%d, data= ", tag, sz);
|
||||
if (off + sz > end) {
|
||||
print(" Error: Invalid extra data, beyond extra length");
|
||||
break;
|
||||
}
|
||||
off += 4;
|
||||
for (int i = 0; i < sz; i++)
|
||||
print("%02x ", extra[off + i]);
|
||||
print("]%n");
|
||||
switch (tag) {
|
||||
case EXTID_ZIP64 :
|
||||
print(" ->ZIP64: ");
|
||||
int pos = off;
|
||||
while (pos + 8 <= off + sz) {
|
||||
print(" *0x%x ", LL(extra, pos));
|
||||
pos += 8;
|
||||
}
|
||||
print("%n");
|
||||
break;
|
||||
case EXTID_NTFS:
|
||||
print(" ->PKWare NTFS%n");
|
||||
// 4 bytes reserved
|
||||
if (SH(extra, off + 4) != 0x0001 || SH(extra, off + 6) != 24)
|
||||
print(" Error: Invalid NTFS sub-tag or subsz");
|
||||
print(" mtime:%tc%n",
|
||||
winToJavaTime(LL(extra, off + 8)));
|
||||
print(" atime:%tc%n",
|
||||
winToJavaTime(LL(extra, off + 16)));
|
||||
print(" ctime:%tc%n",
|
||||
winToJavaTime(LL(extra, off + 24)));
|
||||
break;
|
||||
case EXTID_EXTT:
|
||||
print(" ->Info-ZIP Extended Timestamp: flag=%x%n",extra[off]);
|
||||
pos = off + 1 ;
|
||||
while (pos + 4 <= off + sz) {
|
||||
print(" *%tc%n",
|
||||
unixToJavaTime(LG(extra, pos)));
|
||||
pos += 4;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
print(" ->[tag=%x, size=%d]%n", tag, sz);
|
||||
}
|
||||
off += sz;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.zipfs2;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.time.DateTimeException;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
/**
|
||||
* @author Xueming Shen
|
||||
*/
|
||||
class ZipUtils {
|
||||
|
||||
/*
|
||||
* Writes a 16-bit short to the output stream in little-endian byte order.
|
||||
*/
|
||||
public static void writeShort(OutputStream os, int v) throws IOException {
|
||||
os.write(v & 0xff);
|
||||
os.write((v >>> 8) & 0xff);
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes a 32-bit int to the output stream in little-endian byte order.
|
||||
*/
|
||||
public static void writeInt(OutputStream os, long v) throws IOException {
|
||||
os.write((int)(v & 0xff));
|
||||
os.write((int)((v >>> 8) & 0xff));
|
||||
os.write((int)((v >>> 16) & 0xff));
|
||||
os.write((int)((v >>> 24) & 0xff));
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes a 64-bit int to the output stream in little-endian byte order.
|
||||
*/
|
||||
public static void writeLong(OutputStream os, long v) throws IOException {
|
||||
os.write((int)(v & 0xff));
|
||||
os.write((int)((v >>> 8) & 0xff));
|
||||
os.write((int)((v >>> 16) & 0xff));
|
||||
os.write((int)((v >>> 24) & 0xff));
|
||||
os.write((int)((v >>> 32) & 0xff));
|
||||
os.write((int)((v >>> 40) & 0xff));
|
||||
os.write((int)((v >>> 48) & 0xff));
|
||||
os.write((int)((v >>> 56) & 0xff));
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes an array of bytes to the output stream.
|
||||
*/
|
||||
public static void writeBytes(OutputStream os, byte[] b)
|
||||
throws IOException
|
||||
{
|
||||
os.write(b, 0, b.length);
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes an array of bytes to the output stream.
|
||||
*/
|
||||
public static void writeBytes(OutputStream os, byte[] b, int off, int len)
|
||||
throws IOException
|
||||
{
|
||||
os.write(b, off, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Append a slash at the end, if it does not have one yet
|
||||
*/
|
||||
public static byte[] toDirectoryPath(byte[] dir) {
|
||||
if (dir.length != 0 && dir[dir.length - 1] != '/') {
|
||||
dir = Arrays.copyOf(dir, dir.length + 1);
|
||||
dir[dir.length - 1] = '/';
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts DOS time to Java time (number of milliseconds since epoch).
|
||||
*/
|
||||
public static long dosToJavaTime(long dtime) {
|
||||
int year = (int) (((dtime >> 25) & 0x7f) + 1980);
|
||||
int month = (int) ((dtime >> 21) & 0x0f);
|
||||
int day = (int) ((dtime >> 16) & 0x1f);
|
||||
int hour = (int) ((dtime >> 11) & 0x1f);
|
||||
int minute = (int) ((dtime >> 5) & 0x3f);
|
||||
int second = (int) ((dtime << 1) & 0x3e);
|
||||
|
||||
if (month > 0 && month < 13 && day > 0 && hour < 24 && minute < 60 && second < 60) {
|
||||
try {
|
||||
LocalDateTime ldt = LocalDateTime.of(year, month, day, hour, minute, second);
|
||||
return TimeUnit.MILLISECONDS.convert(ldt.toEpochSecond(
|
||||
ZoneId.systemDefault().getRules().getOffset(ldt)), TimeUnit.SECONDS);
|
||||
} catch (DateTimeException dte) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
return overflowDosToJavaTime(year, month, day, hour, minute, second);
|
||||
}
|
||||
|
||||
/*
|
||||
* Deal with corner cases where an arguably mal-formed DOS time is used
|
||||
*/
|
||||
@SuppressWarnings("deprecation") // Use of Date constructor
|
||||
private static long overflowDosToJavaTime(int year, int month, int day,
|
||||
int hour, int minute, int second) {
|
||||
return new Date(year - 1900, month - 1, day, hour, minute, second).getTime();
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts Java time to DOS time.
|
||||
*/
|
||||
public static long javaToDosTime(long time) {
|
||||
Instant instant = Instant.ofEpochMilli(time);
|
||||
LocalDateTime ldt = LocalDateTime.ofInstant(
|
||||
instant, ZoneId.systemDefault());
|
||||
int year = ldt.getYear() - 1980;
|
||||
if (year < 0) {
|
||||
return (1 << 21) | (1 << 16);
|
||||
}
|
||||
return (year << 25 |
|
||||
ldt.getMonthValue() << 21 |
|
||||
ldt.getDayOfMonth() << 16 |
|
||||
ldt.getHour() << 11 |
|
||||
ldt.getMinute() << 5 |
|
||||
ldt.getSecond() >> 1) & 0xffffffffL;
|
||||
}
|
||||
|
||||
// used to adjust values between Windows and java epoch
|
||||
private static final long WINDOWS_EPOCH_IN_MICROSECONDS = -11644473600000000L;
|
||||
public static final long winToJavaTime(long wtime) {
|
||||
return TimeUnit.MILLISECONDS.convert(
|
||||
wtime / 10 + WINDOWS_EPOCH_IN_MICROSECONDS, TimeUnit.MICROSECONDS);
|
||||
}
|
||||
|
||||
public static final long javaToWinTime(long time) {
|
||||
return (TimeUnit.MICROSECONDS.convert(time, TimeUnit.MILLISECONDS)
|
||||
- WINDOWS_EPOCH_IN_MICROSECONDS) * 10;
|
||||
}
|
||||
|
||||
public static final long unixToJavaTime(long utime) {
|
||||
return TimeUnit.MILLISECONDS.convert(utime, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public static final long javaToUnixTime(long time) {
|
||||
return TimeUnit.SECONDS.convert(time, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
private static final String regexMetaChars = ".^$+{[]|()";
|
||||
private static final String globMetaChars = "\\*?[{";
|
||||
private static boolean isRegexMeta(char c) {
|
||||
return regexMetaChars.indexOf(c) != -1;
|
||||
}
|
||||
private static boolean isGlobMeta(char c) {
|
||||
return globMetaChars.indexOf(c) != -1;
|
||||
}
|
||||
private static char EOL = 0; //TBD
|
||||
private static char next(String glob, int i) {
|
||||
if (i < glob.length()) {
|
||||
return glob.charAt(i);
|
||||
}
|
||||
return EOL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a regex pattern from the given glob expression.
|
||||
*
|
||||
* @throws PatternSyntaxException
|
||||
*/
|
||||
public static String toRegexPattern(String globPattern) {
|
||||
boolean inGroup = false;
|
||||
StringBuilder regex = new StringBuilder("^");
|
||||
|
||||
int i = 0;
|
||||
while (i < globPattern.length()) {
|
||||
char c = globPattern.charAt(i++);
|
||||
switch (c) {
|
||||
case '\\':
|
||||
// escape special characters
|
||||
if (i == globPattern.length()) {
|
||||
throw new PatternSyntaxException("No character to escape",
|
||||
globPattern, i - 1);
|
||||
}
|
||||
char next = globPattern.charAt(i++);
|
||||
if (isGlobMeta(next) || isRegexMeta(next)) {
|
||||
regex.append('\\');
|
||||
}
|
||||
regex.append(next);
|
||||
break;
|
||||
case '/':
|
||||
regex.append(c);
|
||||
break;
|
||||
case '[':
|
||||
// don't match name separator in class
|
||||
regex.append("[[^/]&&[");
|
||||
if (next(globPattern, i) == '^') {
|
||||
// escape the regex negation char if it appears
|
||||
regex.append("\\^");
|
||||
i++;
|
||||
} else {
|
||||
// negation
|
||||
if (next(globPattern, i) == '!') {
|
||||
regex.append('^');
|
||||
i++;
|
||||
}
|
||||
// hyphen allowed at start
|
||||
if (next(globPattern, i) == '-') {
|
||||
regex.append('-');
|
||||
i++;
|
||||
}
|
||||
}
|
||||
boolean hasRangeStart = false;
|
||||
char last = 0;
|
||||
while (i < globPattern.length()) {
|
||||
c = globPattern.charAt(i++);
|
||||
if (c == ']') {
|
||||
break;
|
||||
}
|
||||
if (c == '/') {
|
||||
throw new PatternSyntaxException("Explicit 'name separator' in class",
|
||||
globPattern, i - 1);
|
||||
}
|
||||
// TBD: how to specify ']' in a class?
|
||||
if (c == '\\' || c == '[' ||
|
||||
c == '&' && next(globPattern, i) == '&') {
|
||||
// escape '\', '[' or "&&" for regex class
|
||||
regex.append('\\');
|
||||
}
|
||||
regex.append(c);
|
||||
|
||||
if (c == '-') {
|
||||
if (!hasRangeStart) {
|
||||
throw new PatternSyntaxException("Invalid range",
|
||||
globPattern, i - 1);
|
||||
}
|
||||
if ((c = next(globPattern, i++)) == EOL || c == ']') {
|
||||
break;
|
||||
}
|
||||
if (c < last) {
|
||||
throw new PatternSyntaxException("Invalid range",
|
||||
globPattern, i - 3);
|
||||
}
|
||||
regex.append(c);
|
||||
hasRangeStart = false;
|
||||
} else {
|
||||
hasRangeStart = true;
|
||||
last = c;
|
||||
}
|
||||
}
|
||||
if (c != ']') {
|
||||
throw new PatternSyntaxException("Missing ']", globPattern, i - 1);
|
||||
}
|
||||
regex.append("]]");
|
||||
break;
|
||||
case '{':
|
||||
if (inGroup) {
|
||||
throw new PatternSyntaxException("Cannot nest groups",
|
||||
globPattern, i - 1);
|
||||
}
|
||||
regex.append("(?:(?:");
|
||||
inGroup = true;
|
||||
break;
|
||||
case '}':
|
||||
if (inGroup) {
|
||||
regex.append("))");
|
||||
inGroup = false;
|
||||
} else {
|
||||
regex.append('}');
|
||||
}
|
||||
break;
|
||||
case ',':
|
||||
if (inGroup) {
|
||||
regex.append(")|(?:");
|
||||
} else {
|
||||
regex.append(',');
|
||||
}
|
||||
break;
|
||||
case '*':
|
||||
if (next(globPattern, i) == '*') {
|
||||
// crosses directory boundaries
|
||||
regex.append(".*");
|
||||
i++;
|
||||
} else {
|
||||
// within directory boundary
|
||||
regex.append("[^/]*");
|
||||
}
|
||||
break;
|
||||
case '?':
|
||||
regex.append("[^/]");
|
||||
break;
|
||||
default:
|
||||
if (isRegexMeta(c)) {
|
||||
regex.append('\\');
|
||||
}
|
||||
regex.append(c);
|
||||
}
|
||||
}
|
||||
if (inGroup) {
|
||||
throw new PatternSyntaxException("Missing '}", globPattern, i - 1);
|
||||
}
|
||||
return regex.append('$').toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javac.internal;
|
||||
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Indicates the API declaration in question is associated with a
|
||||
* <em>preview feature</em>. See JEP 12: "Preview Language and VM
|
||||
* Features" (http://openjdk.java.net/jeps/12).
|
||||
*
|
||||
* Note this internal annotation is handled specially by the javac compiler.
|
||||
* To work properly with {@code --release older-release}, it requires special
|
||||
* handling in {@code make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java}
|
||||
* and {@code src/jdk.compiler/share/classes/openjdk/tools/javac/jvm/ClassReader.java}.
|
||||
*
|
||||
* @since 14
|
||||
*/
|
||||
// Match the meaningful targets of java.lang.Deprecated, omit local
|
||||
// variables and parameter declarations
|
||||
@Target({java.lang.annotation.ElementType.METHOD,
|
||||
java.lang.annotation.ElementType.CONSTRUCTOR,
|
||||
java.lang.annotation.ElementType.FIELD,
|
||||
java.lang.annotation.ElementType.PACKAGE,
|
||||
java.lang.annotation.ElementType.TYPE})
|
||||
// CLASS retention will hopefully be sufficient for the purposes at hand
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
// *Not* @Documented
|
||||
public @interface PreviewFeature {
|
||||
/**
|
||||
* Name of the preview feature the annotated API is associated
|
||||
* with.
|
||||
*/
|
||||
public Feature feature();
|
||||
|
||||
public boolean reflective() default false;
|
||||
|
||||
public enum Feature {
|
||||
SWITCH_PATTERN_MATCHING,
|
||||
/**
|
||||
* A key for testing.
|
||||
*/
|
||||
TEST,
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,468 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javac.internal.jimage;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import javac.internal.jimage.decompressor.Decompressor;
|
||||
|
||||
/**
|
||||
* @implNote This class needs to maintain JDK 8 source compatibility.
|
||||
*
|
||||
* It is used internally in the JDK to implement jimage/jrtfs access,
|
||||
* but also compiled and delivered as part of the jrtfs.jar to support access
|
||||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
public class BasicImageReader implements AutoCloseable {
|
||||
@SuppressWarnings("removal")
|
||||
private static boolean isSystemProperty(String key, String value, String def) {
|
||||
// No lambdas during bootstrap
|
||||
return AccessController.doPrivileged(
|
||||
new PrivilegedAction<Boolean>() {
|
||||
@Override
|
||||
public Boolean run() {
|
||||
return value.equals(System.getProperty(key, def));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static private final boolean IS_64_BIT =
|
||||
isSystemProperty("sun.arch.data.model", "64", "32");
|
||||
static private final boolean USE_JVM_MAP =
|
||||
isSystemProperty("jdk.image.use.jvm.map", "true", "true");
|
||||
static private final boolean MAP_ALL =
|
||||
isSystemProperty("jdk.image.map.all", "true", IS_64_BIT ? "true" : "false");
|
||||
|
||||
private final Path imagePath;
|
||||
private final ByteOrder byteOrder;
|
||||
private final String name;
|
||||
private final ByteBuffer memoryMap;
|
||||
private final FileChannel channel;
|
||||
private final ImageHeader header;
|
||||
private final long indexSize;
|
||||
private final IntBuffer redirect;
|
||||
private final IntBuffer offsets;
|
||||
private final ByteBuffer locations;
|
||||
private final ByteBuffer strings;
|
||||
private final ImageStringsReader stringsReader;
|
||||
private final Decompressor decompressor;
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
protected BasicImageReader(Path path, ByteOrder byteOrder)
|
||||
throws IOException {
|
||||
this.imagePath = Objects.requireNonNull(path);
|
||||
this.byteOrder = Objects.requireNonNull(byteOrder);
|
||||
this.name = this.imagePath.toString();
|
||||
|
||||
ByteBuffer map;
|
||||
|
||||
if (USE_JVM_MAP && BasicImageReader.class.getClassLoader() == null) {
|
||||
// Check to see if the jvm has opened the file using libjimage
|
||||
// native entry when loading the image for this runtime
|
||||
map = NativeImageBuffer.getNativeMap(name);
|
||||
} else {
|
||||
map = null;
|
||||
}
|
||||
|
||||
// Open the file only if no memory map yet or is 32 bit jvm
|
||||
if (map != null && MAP_ALL) {
|
||||
channel = null;
|
||||
} else {
|
||||
channel = FileChannel.open(imagePath, StandardOpenOption.READ);
|
||||
// No lambdas during bootstrap
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
@Override
|
||||
public Void run() {
|
||||
if (BasicImageReader.class.getClassLoader() == null) {
|
||||
try {
|
||||
Class<?> fileChannelImpl =
|
||||
Class.forName("sun.nio.ch.FileChannelImpl");
|
||||
Method setUninterruptible =
|
||||
fileChannelImpl.getMethod("setUninterruptible");
|
||||
setUninterruptible.invoke(channel);
|
||||
} catch (ClassNotFoundException |
|
||||
NoSuchMethodException |
|
||||
IllegalAccessException |
|
||||
InvocationTargetException ex) {
|
||||
// fall thru - will only happen on JDK-8 systems where this code
|
||||
// is only used by tools using jrt-fs (non-critical.)
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// If no memory map yet and 64 bit jvm then memory map entire file
|
||||
if (MAP_ALL && map == null) {
|
||||
map = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
|
||||
}
|
||||
|
||||
// Assume we have a memory map to read image file header
|
||||
ByteBuffer headerBuffer = map;
|
||||
int headerSize = ImageHeader.getHeaderSize();
|
||||
|
||||
// If no memory map then read header from image file
|
||||
if (headerBuffer == null) {
|
||||
headerBuffer = ByteBuffer.allocateDirect(headerSize);
|
||||
if (channel.read(headerBuffer, 0L) == headerSize) {
|
||||
headerBuffer.rewind();
|
||||
} else {
|
||||
throw new IOException("\"" + name + "\" is not an image file");
|
||||
}
|
||||
} else if (headerBuffer.capacity() < headerSize) {
|
||||
throw new IOException("\"" + name + "\" is not an image file");
|
||||
}
|
||||
|
||||
// Interpret the image file header
|
||||
header = readHeader(intBuffer(headerBuffer, 0, headerSize));
|
||||
indexSize = header.getIndexSize();
|
||||
|
||||
// If no memory map yet then must be 32 bit jvm not previously mapped
|
||||
if (map == null) {
|
||||
// Just map the image index
|
||||
map = channel.map(FileChannel.MapMode.READ_ONLY, 0, indexSize);
|
||||
}
|
||||
|
||||
memoryMap = map.asReadOnlyBuffer();
|
||||
|
||||
// Interpret the image index
|
||||
if (memoryMap.capacity() < indexSize) {
|
||||
throw new IOException("The image file \"" + name + "\" is corrupted");
|
||||
}
|
||||
redirect = intBuffer(memoryMap, header.getRedirectOffset(), header.getRedirectSize());
|
||||
offsets = intBuffer(memoryMap, header.getOffsetsOffset(), header.getOffsetsSize());
|
||||
locations = slice(memoryMap, header.getLocationsOffset(), header.getLocationsSize());
|
||||
strings = slice(memoryMap, header.getStringsOffset(), header.getStringsSize());
|
||||
|
||||
stringsReader = new ImageStringsReader(this);
|
||||
decompressor = new Decompressor();
|
||||
}
|
||||
|
||||
protected BasicImageReader(Path imagePath) throws IOException {
|
||||
this(imagePath, ByteOrder.nativeOrder());
|
||||
}
|
||||
|
||||
public static BasicImageReader open(Path imagePath) throws IOException {
|
||||
return new BasicImageReader(imagePath, ByteOrder.nativeOrder());
|
||||
}
|
||||
|
||||
public ImageHeader getHeader() {
|
||||
return header;
|
||||
}
|
||||
|
||||
private ImageHeader readHeader(IntBuffer buffer) throws IOException {
|
||||
ImageHeader result = ImageHeader.readFrom(buffer);
|
||||
|
||||
if (result.getMagic() != ImageHeader.MAGIC) {
|
||||
throw new IOException("\"" + name + "\" is not an image file");
|
||||
}
|
||||
|
||||
if (result.getMajorVersion() != ImageHeader.MAJOR_VERSION ||
|
||||
result.getMinorVersion() != ImageHeader.MINOR_VERSION) {
|
||||
throw new IOException("The image file \"" + name + "\" is not " +
|
||||
"the correct version. Major: " + result.getMajorVersion() +
|
||||
". Minor: " + result.getMinorVersion());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static ByteBuffer slice(ByteBuffer buffer, int position, int capacity) {
|
||||
// Note that this is the only limit and position manipulation of
|
||||
// BasicImageReader private ByteBuffers. The synchronize could be avoided
|
||||
// by cloning the buffer to make a local copy, but at the cost of creating
|
||||
// a new object.
|
||||
synchronized(buffer) {
|
||||
buffer.limit(position + capacity);
|
||||
buffer.position(position);
|
||||
return buffer.slice();
|
||||
}
|
||||
}
|
||||
|
||||
private IntBuffer intBuffer(ByteBuffer buffer, int offset, int size) {
|
||||
return slice(buffer, offset, size).order(byteOrder).asIntBuffer();
|
||||
}
|
||||
|
||||
public static void releaseByteBuffer(ByteBuffer buffer) {
|
||||
Objects.requireNonNull(buffer);
|
||||
|
||||
if (!MAP_ALL) {
|
||||
ImageBufferCache.releaseBuffer(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public ByteOrder getByteOrder() {
|
||||
return byteOrder;
|
||||
}
|
||||
|
||||
public Path getImagePath() {
|
||||
return imagePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (channel != null) {
|
||||
channel.close();
|
||||
}
|
||||
}
|
||||
|
||||
public ImageStringsReader getStrings() {
|
||||
return stringsReader;
|
||||
}
|
||||
|
||||
public ImageLocation findLocation(String module, String name) {
|
||||
int index = getLocationIndex(module, name);
|
||||
if (index < 0) {
|
||||
return null;
|
||||
}
|
||||
long[] attributes = getAttributes(offsets.get(index));
|
||||
if (!ImageLocation.verify(module, name, attributes, stringsReader)) {
|
||||
return null;
|
||||
}
|
||||
return new ImageLocation(attributes, stringsReader);
|
||||
}
|
||||
|
||||
public ImageLocation findLocation(String name) {
|
||||
int index = getLocationIndex(name);
|
||||
if (index < 0) {
|
||||
return null;
|
||||
}
|
||||
long[] attributes = getAttributes(offsets.get(index));
|
||||
if (!ImageLocation.verify(name, attributes, stringsReader)) {
|
||||
return null;
|
||||
}
|
||||
return new ImageLocation(attributes, stringsReader);
|
||||
}
|
||||
|
||||
public boolean verifyLocation(String module, String name) {
|
||||
int index = getLocationIndex(module, name);
|
||||
if (index < 0) {
|
||||
return false;
|
||||
}
|
||||
int locationOffset = offsets.get(index);
|
||||
return ImageLocation.verify(module, name, locations, locationOffset, stringsReader);
|
||||
}
|
||||
|
||||
// Details of the algorithm used here can be found in
|
||||
// jdk.tools.jlink.internal.PerfectHashBuilder.
|
||||
public int getLocationIndex(String name) {
|
||||
int count = header.getTableLength();
|
||||
int index = redirect.get(ImageStringsReader.hashCode(name) % count);
|
||||
if (index < 0) {
|
||||
// index is twos complement of location attributes index.
|
||||
return -index - 1;
|
||||
} else if (index > 0) {
|
||||
// index is hash seed needed to compute location attributes index.
|
||||
return ImageStringsReader.hashCode(name, index) % count;
|
||||
} else {
|
||||
// No entry.
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private int getLocationIndex(String module, String name) {
|
||||
int count = header.getTableLength();
|
||||
int index = redirect.get(ImageStringsReader.hashCode(module, name) % count);
|
||||
if (index < 0) {
|
||||
// index is twos complement of location attributes index.
|
||||
return -index - 1;
|
||||
} else if (index > 0) {
|
||||
// index is hash seed needed to compute location attributes index.
|
||||
return ImageStringsReader.hashCode(module, name, index) % count;
|
||||
} else {
|
||||
// No entry.
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public String[] getEntryNames() {
|
||||
int[] attributeOffsets = new int[offsets.capacity()];
|
||||
offsets.get(attributeOffsets);
|
||||
return IntStream.of(attributeOffsets)
|
||||
.filter(o -> o != 0)
|
||||
.mapToObj(o -> ImageLocation.readFrom(this, o).getFullName())
|
||||
.sorted()
|
||||
.toArray(String[]::new);
|
||||
}
|
||||
|
||||
ImageLocation getLocation(int offset) {
|
||||
return ImageLocation.readFrom(this, offset);
|
||||
}
|
||||
|
||||
public long[] getAttributes(int offset) {
|
||||
if (offset < 0 || offset >= locations.limit()) {
|
||||
throw new IndexOutOfBoundsException("offset");
|
||||
}
|
||||
return ImageLocation.decompress(locations, offset);
|
||||
}
|
||||
|
||||
public String getString(int offset) {
|
||||
if (offset < 0 || offset >= strings.limit()) {
|
||||
throw new IndexOutOfBoundsException("offset");
|
||||
}
|
||||
return ImageStringsReader.stringFromByteBuffer(strings, offset);
|
||||
}
|
||||
|
||||
public int match(int offset, String string, int stringOffset) {
|
||||
if (offset < 0 || offset >= strings.limit()) {
|
||||
throw new IndexOutOfBoundsException("offset");
|
||||
}
|
||||
return ImageStringsReader.stringFromByteBufferMatches(strings, offset, string, stringOffset);
|
||||
}
|
||||
|
||||
private byte[] getBufferBytes(ByteBuffer buffer) {
|
||||
Objects.requireNonNull(buffer);
|
||||
byte[] bytes = new byte[buffer.limit()];
|
||||
buffer.get(bytes);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private ByteBuffer readBuffer(long offset, long size) {
|
||||
if (offset < 0 || Integer.MAX_VALUE <= offset) {
|
||||
throw new IndexOutOfBoundsException("Bad offset: " + offset);
|
||||
}
|
||||
|
||||
if (size < 0 || Integer.MAX_VALUE <= size) {
|
||||
throw new IndexOutOfBoundsException("Bad size: " + size);
|
||||
}
|
||||
|
||||
if (MAP_ALL) {
|
||||
ByteBuffer buffer = slice(memoryMap, (int)offset, (int)size);
|
||||
buffer.order(ByteOrder.BIG_ENDIAN);
|
||||
|
||||
return buffer;
|
||||
} else {
|
||||
if (channel == null) {
|
||||
throw new InternalError("Image file channel not open");
|
||||
}
|
||||
|
||||
ByteBuffer buffer = ImageBufferCache.getBuffer(size);
|
||||
int read;
|
||||
try {
|
||||
read = channel.read(buffer, offset);
|
||||
buffer.rewind();
|
||||
} catch (IOException ex) {
|
||||
ImageBufferCache.releaseBuffer(buffer);
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
if (read != size) {
|
||||
ImageBufferCache.releaseBuffer(buffer);
|
||||
throw new RuntimeException("Short read: " + read +
|
||||
" instead of " + size + " bytes");
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getResource(String name) {
|
||||
Objects.requireNonNull(name);
|
||||
ImageLocation location = findLocation(name);
|
||||
|
||||
return location != null ? getResource(location) : null;
|
||||
}
|
||||
|
||||
public byte[] getResource(ImageLocation loc) {
|
||||
ByteBuffer buffer = getResourceBuffer(loc);
|
||||
|
||||
if (buffer != null) {
|
||||
byte[] bytes = getBufferBytes(buffer);
|
||||
ImageBufferCache.releaseBuffer(buffer);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public ByteBuffer getResourceBuffer(ImageLocation loc) {
|
||||
Objects.requireNonNull(loc);
|
||||
long offset = loc.getContentOffset() + indexSize;
|
||||
long compressedSize = loc.getCompressedSize();
|
||||
long uncompressedSize = loc.getUncompressedSize();
|
||||
|
||||
if (compressedSize < 0 || Integer.MAX_VALUE < compressedSize) {
|
||||
throw new IndexOutOfBoundsException(
|
||||
"Bad compressed size: " + compressedSize);
|
||||
}
|
||||
|
||||
if (uncompressedSize < 0 || Integer.MAX_VALUE < uncompressedSize) {
|
||||
throw new IndexOutOfBoundsException(
|
||||
"Bad uncompressed size: " + uncompressedSize);
|
||||
}
|
||||
|
||||
if (compressedSize == 0) {
|
||||
return readBuffer(offset, uncompressedSize);
|
||||
} else {
|
||||
ByteBuffer buffer = readBuffer(offset, compressedSize);
|
||||
|
||||
if (buffer != null) {
|
||||
byte[] bytesIn = getBufferBytes(buffer);
|
||||
ImageBufferCache.releaseBuffer(buffer);
|
||||
byte[] bytesOut;
|
||||
|
||||
try {
|
||||
bytesOut = decompressor.decompressResource(byteOrder,
|
||||
(int strOffset) -> getString(strOffset), bytesIn);
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
return ByteBuffer.wrap(bytesOut);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public InputStream getResourceStream(ImageLocation loc) {
|
||||
Objects.requireNonNull(loc);
|
||||
byte[] bytes = getResource(loc);
|
||||
|
||||
return new ByteArrayInputStream(bytes);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javac.internal.jimage;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @implNote This class needs to maintain JDK 8 source compatibility.
|
||||
*
|
||||
* It is used internally in the JDK to implement jimage/jrtfs access,
|
||||
* but also compiled and delivered as part of the jrt-fs.jar to support access
|
||||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
class ImageBufferCache {
|
||||
private static final int MAX_CACHED_BUFFERS = 3;
|
||||
private static final int LARGE_BUFFER = 0x10000;
|
||||
|
||||
/*
|
||||
* We used to have a class BufferReference extending from WeakReference<ByteBuffer>.
|
||||
* BufferReference class had an instance field called "capacity". This field was
|
||||
* used to make DECREASING_CAPACITY_NULLS_LAST comparator stable in the presence
|
||||
* of GC clearing the WeakReference concurrently.
|
||||
*
|
||||
* But this scheme results in metaspace leak. The thread local is alive till the
|
||||
* the thread is alive. And so ImageBufferCache$BufferReference class was kept alive.
|
||||
* Because this class and ImageBufferCache$BufferReference are all loaded by a URL
|
||||
* class loader from jrt-fs.jar, the class loader and so all the classes loaded by it
|
||||
* were alive!
|
||||
*
|
||||
* Solution is to avoid using a URL loader loaded class type with thread local. All we
|
||||
* need is a pair of WeakReference<ByteBuffer>, Integer (saved capacity for stability
|
||||
* of comparator). We use Map.Entry as pair implementation. With this, all types used
|
||||
* with thread local are bootstrap types and so no metaspace leak.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static final ThreadLocal<Map.Entry<WeakReference<ByteBuffer>, Integer>[]> CACHE =
|
||||
new ThreadLocal<Map.Entry<WeakReference<ByteBuffer>, Integer>[]>() {
|
||||
@Override
|
||||
protected Map.Entry<WeakReference<ByteBuffer>, Integer>[] initialValue() {
|
||||
// 1 extra slot to simplify logic of releaseBuffer()
|
||||
return (Map.Entry<WeakReference<ByteBuffer>, Integer>[])new Map.Entry<?,?>[MAX_CACHED_BUFFERS + 1];
|
||||
}
|
||||
};
|
||||
|
||||
private static ByteBuffer allocateBuffer(long size) {
|
||||
return ByteBuffer.allocateDirect((int)((size + 0xFFF) & ~0xFFF));
|
||||
}
|
||||
|
||||
static ByteBuffer getBuffer(long size) {
|
||||
if (size < 0 || Integer.MAX_VALUE < size) {
|
||||
throw new IndexOutOfBoundsException("size");
|
||||
}
|
||||
|
||||
ByteBuffer result = null;
|
||||
|
||||
if (size > LARGE_BUFFER) {
|
||||
result = allocateBuffer(size);
|
||||
} else {
|
||||
Map.Entry<WeakReference<ByteBuffer>, Integer>[] cache = CACHE.get();
|
||||
|
||||
// buffers are ordered by decreasing capacity
|
||||
// cache[MAX_CACHED_BUFFERS] is always null
|
||||
for (int i = MAX_CACHED_BUFFERS - 1; i >= 0; i--) {
|
||||
Map.Entry<WeakReference<ByteBuffer>, Integer> reference = cache[i];
|
||||
|
||||
if (reference != null) {
|
||||
ByteBuffer buffer = getByteBuffer(reference);
|
||||
|
||||
if (buffer != null && size <= buffer.capacity()) {
|
||||
cache[i] = null;
|
||||
result = buffer;
|
||||
result.rewind();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
result = allocateBuffer(size);
|
||||
}
|
||||
}
|
||||
|
||||
result.limit((int)size);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void releaseBuffer(ByteBuffer buffer) {
|
||||
if (buffer.capacity() > LARGE_BUFFER) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map.Entry<WeakReference<ByteBuffer>, Integer>[] cache = CACHE.get();
|
||||
|
||||
// expunge cleared BufferRef(s)
|
||||
for (int i = 0; i < MAX_CACHED_BUFFERS; i++) {
|
||||
Map.Entry<WeakReference<ByteBuffer>, Integer> reference = cache[i];
|
||||
if (reference != null && getByteBuffer(reference) == null) {
|
||||
cache[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
// insert buffer back with new BufferRef wrapping it
|
||||
cache[MAX_CACHED_BUFFERS] = newCacheEntry(buffer);
|
||||
Arrays.sort(cache, DECREASING_CAPACITY_NULLS_LAST);
|
||||
// squeeze the smallest one out
|
||||
cache[MAX_CACHED_BUFFERS] = null;
|
||||
}
|
||||
|
||||
private static Map.Entry<WeakReference<ByteBuffer>, Integer> newCacheEntry(ByteBuffer bb) {
|
||||
return new AbstractMap.SimpleEntry<WeakReference<ByteBuffer>, Integer>(
|
||||
new WeakReference<ByteBuffer>(bb), bb.capacity());
|
||||
}
|
||||
|
||||
private static int getCapacity(Map.Entry<WeakReference<ByteBuffer>, Integer> e) {
|
||||
return e == null? 0 : e.getValue();
|
||||
}
|
||||
|
||||
private static ByteBuffer getByteBuffer(Map.Entry<WeakReference<ByteBuffer>, Integer> e) {
|
||||
return e == null? null : e.getKey().get();
|
||||
}
|
||||
|
||||
private static Comparator<Map.Entry<WeakReference<ByteBuffer>, Integer>> DECREASING_CAPACITY_NULLS_LAST =
|
||||
new Comparator<Map.Entry<WeakReference<ByteBuffer>, Integer>>() {
|
||||
@Override
|
||||
public int compare(Map.Entry<WeakReference<ByteBuffer>, Integer> br1,
|
||||
Map.Entry<WeakReference<ByteBuffer>, Integer> br2) {
|
||||
return Integer.compare(getCapacity(br1), getCapacity(br2));
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javac.internal.jimage;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @implNote This class needs to maintain JDK 8 source compatibility.
|
||||
*
|
||||
* It is used internally in the JDK to implement jimage/jrtfs access,
|
||||
* but also compiled and delivered as part of the jrtfs.jar to support access
|
||||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
public final class ImageHeader {
|
||||
public static final int MAGIC = 0xCAFEDADA;
|
||||
public static final int MAJOR_VERSION = 1;
|
||||
public static final int MINOR_VERSION = 0;
|
||||
private static final int HEADER_SLOTS = 7;
|
||||
|
||||
private final int magic;
|
||||
private final int majorVersion;
|
||||
private final int minorVersion;
|
||||
private final int flags;
|
||||
private final int resourceCount;
|
||||
private final int tableLength;
|
||||
private final int locationsSize;
|
||||
private final int stringsSize;
|
||||
|
||||
public ImageHeader(int resourceCount, int tableCount,
|
||||
int locationsSize, int stringsSize) {
|
||||
this(MAGIC, MAJOR_VERSION, MINOR_VERSION, 0, resourceCount,
|
||||
tableCount, locationsSize, stringsSize);
|
||||
}
|
||||
|
||||
public ImageHeader(int magic, int majorVersion, int minorVersion,
|
||||
int flags, int resourceCount,
|
||||
int tableLength, int locationsSize, int stringsSize)
|
||||
{
|
||||
this.magic = magic;
|
||||
this.majorVersion = majorVersion;
|
||||
this.minorVersion = minorVersion;
|
||||
this.flags = flags;
|
||||
this.resourceCount = resourceCount;
|
||||
this.tableLength = tableLength;
|
||||
this.locationsSize = locationsSize;
|
||||
this.stringsSize = stringsSize;
|
||||
}
|
||||
|
||||
public static int getHeaderSize() {
|
||||
return HEADER_SLOTS * 4;
|
||||
}
|
||||
|
||||
static ImageHeader readFrom(IntBuffer buffer) {
|
||||
Objects.requireNonNull(buffer);
|
||||
|
||||
if (buffer.capacity() != HEADER_SLOTS) {
|
||||
throw new InternalError(
|
||||
"jimage header not the correct size: " + buffer.capacity());
|
||||
}
|
||||
|
||||
int magic = buffer.get(0);
|
||||
int version = buffer.get(1);
|
||||
int majorVersion = version >>> 16;
|
||||
int minorVersion = version & 0xFFFF;
|
||||
int flags = buffer.get(2);
|
||||
int resourceCount = buffer.get(3);
|
||||
int tableLength = buffer.get(4);
|
||||
int locationsSize = buffer.get(5);
|
||||
int stringsSize = buffer.get(6);
|
||||
|
||||
return new ImageHeader(magic, majorVersion, minorVersion, flags,
|
||||
resourceCount, tableLength, locationsSize, stringsSize);
|
||||
}
|
||||
|
||||
public void writeTo(ImageStream stream) {
|
||||
Objects.requireNonNull(stream);
|
||||
stream.ensure(getHeaderSize());
|
||||
writeTo(stream.getBuffer());
|
||||
}
|
||||
|
||||
public void writeTo(ByteBuffer buffer) {
|
||||
Objects.requireNonNull(buffer);
|
||||
buffer.putInt(magic);
|
||||
buffer.putInt(majorVersion << 16 | minorVersion);
|
||||
buffer.putInt(flags);
|
||||
buffer.putInt(resourceCount);
|
||||
buffer.putInt(tableLength);
|
||||
buffer.putInt(locationsSize);
|
||||
buffer.putInt(stringsSize);
|
||||
}
|
||||
|
||||
public int getMagic() {
|
||||
return magic;
|
||||
}
|
||||
|
||||
public int getMajorVersion() {
|
||||
return majorVersion;
|
||||
}
|
||||
|
||||
public int getMinorVersion() {
|
||||
return minorVersion;
|
||||
}
|
||||
|
||||
public int getFlags() {
|
||||
return flags;
|
||||
}
|
||||
|
||||
public int getResourceCount() {
|
||||
return resourceCount;
|
||||
}
|
||||
|
||||
public int getTableLength() {
|
||||
return tableLength;
|
||||
}
|
||||
|
||||
public int getRedirectSize() {
|
||||
return tableLength * 4;
|
||||
}
|
||||
|
||||
public int getOffsetsSize() {
|
||||
return tableLength * 4;
|
||||
}
|
||||
|
||||
public int getLocationsSize() {
|
||||
return locationsSize;
|
||||
}
|
||||
|
||||
public int getStringsSize() {
|
||||
return stringsSize;
|
||||
}
|
||||
|
||||
public int getIndexSize() {
|
||||
return getHeaderSize() +
|
||||
getRedirectSize() +
|
||||
getOffsetsSize() +
|
||||
getLocationsSize() +
|
||||
getStringsSize();
|
||||
}
|
||||
|
||||
int getRedirectOffset() {
|
||||
return getHeaderSize();
|
||||
}
|
||||
|
||||
int getOffsetsOffset() {
|
||||
return getRedirectOffset() +
|
||||
getRedirectSize();
|
||||
}
|
||||
|
||||
int getLocationsOffset() {
|
||||
return getOffsetsOffset() +
|
||||
getOffsetsSize();
|
||||
}
|
||||
|
||||
int getStringsOffset() {
|
||||
return getLocationsOffset() +
|
||||
getLocationsSize();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,369 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javac.internal.jimage;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @implNote This class needs to maintain JDK 8 source compatibility.
|
||||
*
|
||||
* It is used internally in the JDK to implement jimage/jrtfs access,
|
||||
* but also compiled and delivered as part of the jrtfs.jar to support access
|
||||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
public class ImageLocation {
|
||||
public static final int ATTRIBUTE_END = 0;
|
||||
public static final int ATTRIBUTE_MODULE = 1;
|
||||
public static final int ATTRIBUTE_PARENT = 2;
|
||||
public static final int ATTRIBUTE_BASE = 3;
|
||||
public static final int ATTRIBUTE_EXTENSION = 4;
|
||||
public static final int ATTRIBUTE_OFFSET = 5;
|
||||
public static final int ATTRIBUTE_COMPRESSED = 6;
|
||||
public static final int ATTRIBUTE_UNCOMPRESSED = 7;
|
||||
public static final int ATTRIBUTE_COUNT = 8;
|
||||
|
||||
protected final long[] attributes;
|
||||
|
||||
protected final ImageStrings strings;
|
||||
|
||||
public ImageLocation(long[] attributes, ImageStrings strings) {
|
||||
this.attributes = Objects.requireNonNull(attributes);
|
||||
this.strings = Objects.requireNonNull(strings);
|
||||
}
|
||||
|
||||
ImageStrings getStrings() {
|
||||
return strings;
|
||||
}
|
||||
|
||||
static long[] decompress(ByteBuffer bytes, int offset) {
|
||||
Objects.requireNonNull(bytes);
|
||||
long[] attributes = new long[ATTRIBUTE_COUNT];
|
||||
|
||||
int limit = bytes.limit();
|
||||
while (offset < limit) {
|
||||
int data = bytes.get(offset++) & 0xFF;
|
||||
if (data <= 0x7) { // ATTRIBUTE_END
|
||||
break;
|
||||
}
|
||||
int kind = data >>> 3;
|
||||
if (ATTRIBUTE_COUNT <= kind) {
|
||||
throw new InternalError(
|
||||
"Invalid jimage attribute kind: " + kind);
|
||||
}
|
||||
|
||||
int length = (data & 0x7) + 1;
|
||||
attributes[kind] = readValue(length, bytes, offset, limit);
|
||||
offset += length;
|
||||
}
|
||||
return attributes;
|
||||
}
|
||||
|
||||
public static byte[] compress(long[] attributes) {
|
||||
Objects.requireNonNull(attributes);
|
||||
ImageStream stream = new ImageStream(16);
|
||||
|
||||
for (int kind = ATTRIBUTE_END + 1; kind < ATTRIBUTE_COUNT; kind++) {
|
||||
long value = attributes[kind];
|
||||
|
||||
if (value != 0) {
|
||||
int n = (63 - Long.numberOfLeadingZeros(value)) >> 3;
|
||||
stream.put((kind << 3) | n);
|
||||
|
||||
for (int i = n; i >= 0; i--) {
|
||||
stream.put((int)(value >> (i << 3)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stream.put(ATTRIBUTE_END << 3);
|
||||
|
||||
return stream.toArray();
|
||||
}
|
||||
|
||||
public boolean verify(String name) {
|
||||
return verify(name, attributes, strings);
|
||||
}
|
||||
|
||||
/**
|
||||
* A simpler verification would be {@code name.equals(getFullName())}, but
|
||||
* by not creating the full name and enabling early returns we allocate
|
||||
* fewer objects.
|
||||
*/
|
||||
static boolean verify(String name, long[] attributes, ImageStrings strings) {
|
||||
Objects.requireNonNull(name);
|
||||
final int length = name.length();
|
||||
int index = 0;
|
||||
int moduleOffset = (int)attributes[ATTRIBUTE_MODULE];
|
||||
if (moduleOffset != 0 && length >= 1) {
|
||||
int moduleLen = strings.match(moduleOffset, name, 1);
|
||||
index = moduleLen + 1;
|
||||
if (moduleLen < 0
|
||||
|| length <= index
|
||||
|| name.charAt(0) != '/'
|
||||
|| name.charAt(index++) != '/') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return verifyName(null, name, index, length, 0,
|
||||
(int) attributes[ATTRIBUTE_PARENT],
|
||||
(int) attributes[ATTRIBUTE_BASE],
|
||||
(int) attributes[ATTRIBUTE_EXTENSION],
|
||||
strings);
|
||||
}
|
||||
|
||||
static boolean verify(String module, String name, ByteBuffer locations,
|
||||
int locationOffset, ImageStrings strings) {
|
||||
int moduleOffset = 0;
|
||||
int parentOffset = 0;
|
||||
int baseOffset = 0;
|
||||
int extOffset = 0;
|
||||
|
||||
int limit = locations.limit();
|
||||
while (locationOffset < limit) {
|
||||
int data = locations.get(locationOffset++) & 0xFF;
|
||||
if (data <= 0x7) { // ATTRIBUTE_END
|
||||
break;
|
||||
}
|
||||
int kind = data >>> 3;
|
||||
if (ATTRIBUTE_COUNT <= kind) {
|
||||
throw new InternalError(
|
||||
"Invalid jimage attribute kind: " + kind);
|
||||
}
|
||||
|
||||
int length = (data & 0x7) + 1;
|
||||
switch (kind) {
|
||||
case ATTRIBUTE_MODULE:
|
||||
moduleOffset = (int) readValue(length, locations, locationOffset, limit);
|
||||
break;
|
||||
case ATTRIBUTE_BASE:
|
||||
baseOffset = (int) readValue(length, locations, locationOffset, limit);
|
||||
break;
|
||||
case ATTRIBUTE_PARENT:
|
||||
parentOffset = (int) readValue(length, locations, locationOffset, limit);
|
||||
break;
|
||||
case ATTRIBUTE_EXTENSION:
|
||||
extOffset = (int) readValue(length, locations, locationOffset, limit);
|
||||
break;
|
||||
}
|
||||
locationOffset += length;
|
||||
}
|
||||
return verifyName(module, name, 0, name.length(),
|
||||
moduleOffset, parentOffset, baseOffset, extOffset, strings);
|
||||
}
|
||||
|
||||
private static long readValue(int length, ByteBuffer buffer, int offset, int limit) {
|
||||
long value = 0;
|
||||
for (int j = 0; j < length; j++) {
|
||||
value <<= 8;
|
||||
if (offset >= limit) {
|
||||
throw new InternalError("Missing jimage attribute data");
|
||||
}
|
||||
value |= buffer.get(offset++) & 0xFF;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static boolean verify(String module, String name, long[] attributes,
|
||||
ImageStrings strings) {
|
||||
Objects.requireNonNull(module);
|
||||
Objects.requireNonNull(name);
|
||||
return verifyName(module, name, 0, name.length(),
|
||||
(int) attributes[ATTRIBUTE_MODULE],
|
||||
(int) attributes[ATTRIBUTE_PARENT],
|
||||
(int) attributes[ATTRIBUTE_BASE],
|
||||
(int) attributes[ATTRIBUTE_EXTENSION],
|
||||
strings);
|
||||
}
|
||||
|
||||
private static boolean verifyName(String module, String name, int index, int length,
|
||||
int moduleOffset, int parentOffset, int baseOffset, int extOffset, ImageStrings strings) {
|
||||
|
||||
if (moduleOffset != 0) {
|
||||
if (strings.match(moduleOffset, module, 0) != module.length()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (parentOffset != 0) {
|
||||
int parentLen = strings.match(parentOffset, name, index);
|
||||
if (parentLen < 0) {
|
||||
return false;
|
||||
}
|
||||
index += parentLen;
|
||||
if (length <= index || name.charAt(index++) != '/') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
int baseLen = strings.match(baseOffset, name, index);
|
||||
if (baseLen < 0) {
|
||||
return false;
|
||||
}
|
||||
index += baseLen;
|
||||
if (extOffset != 0) {
|
||||
if (length <= index
|
||||
|| name.charAt(index++) != '.') {
|
||||
return false;
|
||||
}
|
||||
|
||||
int extLen = strings.match(extOffset, name, index);
|
||||
if (extLen < 0) {
|
||||
return false;
|
||||
}
|
||||
index += extLen;
|
||||
}
|
||||
return length == index;
|
||||
}
|
||||
|
||||
long getAttribute(int kind) {
|
||||
if (kind < ATTRIBUTE_END || ATTRIBUTE_COUNT <= kind) {
|
||||
throw new InternalError(
|
||||
"Invalid jimage attribute kind: " + kind);
|
||||
}
|
||||
return attributes[kind];
|
||||
}
|
||||
|
||||
String getAttributeString(int kind) {
|
||||
if (kind < ATTRIBUTE_END || ATTRIBUTE_COUNT <= kind) {
|
||||
throw new InternalError(
|
||||
"Invalid jimage attribute kind: " + kind);
|
||||
}
|
||||
return getStrings().get((int)attributes[kind]);
|
||||
}
|
||||
|
||||
public String getModule() {
|
||||
return getAttributeString(ATTRIBUTE_MODULE);
|
||||
}
|
||||
|
||||
public int getModuleOffset() {
|
||||
return (int)getAttribute(ATTRIBUTE_MODULE);
|
||||
}
|
||||
|
||||
public String getBase() {
|
||||
return getAttributeString(ATTRIBUTE_BASE);
|
||||
}
|
||||
|
||||
public int getBaseOffset() {
|
||||
return (int)getAttribute(ATTRIBUTE_BASE);
|
||||
}
|
||||
|
||||
public String getParent() {
|
||||
return getAttributeString(ATTRIBUTE_PARENT);
|
||||
}
|
||||
|
||||
public int getParentOffset() {
|
||||
return (int)getAttribute(ATTRIBUTE_PARENT);
|
||||
}
|
||||
|
||||
public String getExtension() {
|
||||
return getAttributeString(ATTRIBUTE_EXTENSION);
|
||||
}
|
||||
|
||||
public int getExtensionOffset() {
|
||||
return (int)getAttribute(ATTRIBUTE_EXTENSION);
|
||||
}
|
||||
|
||||
public String getFullName() {
|
||||
return getFullName(false);
|
||||
}
|
||||
|
||||
public String getFullName(boolean modulesPrefix) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
if (getModuleOffset() != 0) {
|
||||
if (modulesPrefix) {
|
||||
builder.append("/modules");
|
||||
}
|
||||
|
||||
builder.append('/');
|
||||
builder.append(getModule());
|
||||
builder.append('/');
|
||||
}
|
||||
|
||||
if (getParentOffset() != 0) {
|
||||
builder.append(getParent());
|
||||
builder.append('/');
|
||||
}
|
||||
|
||||
builder.append(getBase());
|
||||
|
||||
if (getExtensionOffset() != 0) {
|
||||
builder.append('.');
|
||||
builder.append(getExtension());
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
String buildName(boolean includeModule, boolean includeParent,
|
||||
boolean includeName) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
if (includeModule && getModuleOffset() != 0) {
|
||||
builder.append("/modules/");
|
||||
builder.append(getModule());
|
||||
}
|
||||
|
||||
if (includeParent && getParentOffset() != 0) {
|
||||
builder.append('/');
|
||||
builder.append(getParent());
|
||||
}
|
||||
|
||||
if (includeName) {
|
||||
if (includeModule || includeParent) {
|
||||
builder.append('/');
|
||||
}
|
||||
|
||||
builder.append(getBase());
|
||||
|
||||
if (getExtensionOffset() != 0) {
|
||||
builder.append('.');
|
||||
builder.append(getExtension());
|
||||
}
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public long getContentOffset() {
|
||||
return getAttribute(ATTRIBUTE_OFFSET);
|
||||
}
|
||||
|
||||
public long getCompressedSize() {
|
||||
return getAttribute(ATTRIBUTE_COMPRESSED);
|
||||
}
|
||||
|
||||
public long getUncompressedSize() {
|
||||
return getAttribute(ATTRIBUTE_UNCOMPRESSED);
|
||||
}
|
||||
|
||||
static ImageLocation readFrom(BasicImageReader reader, int offset) {
|
||||
Objects.requireNonNull(reader);
|
||||
long[] attributes = reader.getAttributes(offset);
|
||||
ImageStringsReader strings = reader.getStrings();
|
||||
|
||||
return new ImageLocation(attributes, strings);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,853 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javac.internal.jimage;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* @implNote This class needs to maintain JDK 8 source compatibility.
|
||||
*
|
||||
* It is used internally in the JDK to implement jimage/jrtfs access,
|
||||
* but also compiled and delivered as part of the jrtfs.jar to support access
|
||||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
public final class ImageReader implements AutoCloseable {
|
||||
private final SharedImageReader reader;
|
||||
|
||||
private volatile boolean closed;
|
||||
|
||||
private ImageReader(SharedImageReader reader) {
|
||||
this.reader = reader;
|
||||
}
|
||||
|
||||
public static ImageReader open(Path imagePath, ByteOrder byteOrder) throws IOException {
|
||||
Objects.requireNonNull(imagePath);
|
||||
Objects.requireNonNull(byteOrder);
|
||||
|
||||
return SharedImageReader.open(imagePath, byteOrder);
|
||||
}
|
||||
|
||||
public static ImageReader open(Path imagePath) throws IOException {
|
||||
return open(imagePath, ByteOrder.nativeOrder());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException("image file already closed");
|
||||
}
|
||||
reader.close(this);
|
||||
closed = true;
|
||||
}
|
||||
|
||||
private void ensureOpen() throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException("image file closed");
|
||||
}
|
||||
}
|
||||
|
||||
private void requireOpen() {
|
||||
if (closed) {
|
||||
throw new IllegalStateException("image file closed");
|
||||
}
|
||||
}
|
||||
|
||||
// directory management interface
|
||||
public Directory getRootDirectory() throws IOException {
|
||||
ensureOpen();
|
||||
return reader.getRootDirectory();
|
||||
}
|
||||
|
||||
|
||||
public Node findNode(String name) throws IOException {
|
||||
ensureOpen();
|
||||
return reader.findNode(name);
|
||||
}
|
||||
|
||||
public byte[] getResource(Node node) throws IOException {
|
||||
ensureOpen();
|
||||
return reader.getResource(node);
|
||||
}
|
||||
|
||||
public byte[] getResource(Resource rs) throws IOException {
|
||||
ensureOpen();
|
||||
return reader.getResource(rs);
|
||||
}
|
||||
|
||||
public ImageHeader getHeader() {
|
||||
requireOpen();
|
||||
return reader.getHeader();
|
||||
}
|
||||
|
||||
public static void releaseByteBuffer(ByteBuffer buffer) {
|
||||
BasicImageReader.releaseByteBuffer(buffer);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
requireOpen();
|
||||
return reader.getName();
|
||||
}
|
||||
|
||||
public ByteOrder getByteOrder() {
|
||||
requireOpen();
|
||||
return reader.getByteOrder();
|
||||
}
|
||||
|
||||
public Path getImagePath() {
|
||||
requireOpen();
|
||||
return reader.getImagePath();
|
||||
}
|
||||
|
||||
public ImageStringsReader getStrings() {
|
||||
requireOpen();
|
||||
return reader.getStrings();
|
||||
}
|
||||
|
||||
public ImageLocation findLocation(String mn, String rn) {
|
||||
requireOpen();
|
||||
return reader.findLocation(mn, rn);
|
||||
}
|
||||
|
||||
public boolean verifyLocation(String mn, String rn) {
|
||||
requireOpen();
|
||||
return reader.verifyLocation(mn, rn);
|
||||
}
|
||||
|
||||
public ImageLocation findLocation(String name) {
|
||||
requireOpen();
|
||||
return reader.findLocation(name);
|
||||
}
|
||||
|
||||
public String[] getEntryNames() {
|
||||
requireOpen();
|
||||
return reader.getEntryNames();
|
||||
}
|
||||
|
||||
public String[] getModuleNames() {
|
||||
requireOpen();
|
||||
int off = "/modules/".length();
|
||||
return reader.findNode("/modules")
|
||||
.getChildren()
|
||||
.stream()
|
||||
.map(Node::getNameString)
|
||||
.map(s -> s.substring(off, s.length()))
|
||||
.toArray(String[]::new);
|
||||
}
|
||||
|
||||
public long[] getAttributes(int offset) {
|
||||
requireOpen();
|
||||
return reader.getAttributes(offset);
|
||||
}
|
||||
|
||||
public String getString(int offset) {
|
||||
requireOpen();
|
||||
return reader.getString(offset);
|
||||
}
|
||||
|
||||
public byte[] getResource(String name) {
|
||||
requireOpen();
|
||||
return reader.getResource(name);
|
||||
}
|
||||
|
||||
public byte[] getResource(ImageLocation loc) {
|
||||
requireOpen();
|
||||
return reader.getResource(loc);
|
||||
}
|
||||
|
||||
public ByteBuffer getResourceBuffer(ImageLocation loc) {
|
||||
requireOpen();
|
||||
return reader.getResourceBuffer(loc);
|
||||
}
|
||||
|
||||
public InputStream getResourceStream(ImageLocation loc) {
|
||||
requireOpen();
|
||||
return reader.getResourceStream(loc);
|
||||
}
|
||||
|
||||
private static final class SharedImageReader extends BasicImageReader {
|
||||
static final int SIZE_OF_OFFSET = Integer.BYTES;
|
||||
|
||||
static final Map<Path, SharedImageReader> OPEN_FILES = new HashMap<>();
|
||||
|
||||
// List of openers for this shared image.
|
||||
final Set<ImageReader> openers;
|
||||
|
||||
// attributes of the .jimage file. jimage file does not contain
|
||||
// attributes for the individual resources (yet). We use attributes
|
||||
// of the jimage file itself (creation, modification, access times).
|
||||
// Iniitalized lazily, see {@link #imageFileAttributes()}.
|
||||
BasicFileAttributes imageFileAttributes;
|
||||
|
||||
// directory management implementation
|
||||
final HashMap<String, Node> nodes;
|
||||
volatile Directory rootDir;
|
||||
|
||||
Directory packagesDir;
|
||||
Directory modulesDir;
|
||||
|
||||
private SharedImageReader(Path imagePath, ByteOrder byteOrder) throws IOException {
|
||||
super(imagePath, byteOrder);
|
||||
this.openers = new HashSet<>();
|
||||
this.nodes = new HashMap<>();
|
||||
}
|
||||
|
||||
public static ImageReader open(Path imagePath, ByteOrder byteOrder) throws IOException {
|
||||
Objects.requireNonNull(imagePath);
|
||||
Objects.requireNonNull(byteOrder);
|
||||
|
||||
synchronized (OPEN_FILES) {
|
||||
SharedImageReader reader = OPEN_FILES.get(imagePath);
|
||||
|
||||
if (reader == null) {
|
||||
// Will fail with an IOException if wrong byteOrder.
|
||||
reader = new SharedImageReader(imagePath, byteOrder);
|
||||
OPEN_FILES.put(imagePath, reader);
|
||||
} else if (reader.getByteOrder() != byteOrder) {
|
||||
throw new IOException("\"" + reader.getName() + "\" is not an image file");
|
||||
}
|
||||
|
||||
ImageReader image = new ImageReader(reader);
|
||||
reader.openers.add(image);
|
||||
|
||||
return image;
|
||||
}
|
||||
}
|
||||
|
||||
public void close(ImageReader image) throws IOException {
|
||||
Objects.requireNonNull(image);
|
||||
|
||||
synchronized (OPEN_FILES) {
|
||||
if (!openers.remove(image)) {
|
||||
throw new IOException("image file already closed");
|
||||
}
|
||||
|
||||
if (openers.isEmpty()) {
|
||||
close();
|
||||
nodes.clear();
|
||||
rootDir = null;
|
||||
|
||||
if (!OPEN_FILES.remove(this.getImagePath(), this)) {
|
||||
throw new IOException("image file not found in open list");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void addOpener(ImageReader reader) {
|
||||
synchronized (OPEN_FILES) {
|
||||
openers.add(reader);
|
||||
}
|
||||
}
|
||||
|
||||
boolean removeOpener(ImageReader reader) {
|
||||
synchronized (OPEN_FILES) {
|
||||
return openers.remove(reader);
|
||||
}
|
||||
}
|
||||
|
||||
// directory management interface
|
||||
Directory getRootDirectory() {
|
||||
return buildRootDirectory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazily build a node from a name.
|
||||
*/
|
||||
synchronized Node buildNode(String name) {
|
||||
Node n;
|
||||
boolean isPackages = name.startsWith("/packages");
|
||||
boolean isModules = !isPackages && name.startsWith("/modules");
|
||||
|
||||
if (!(isModules || isPackages)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ImageLocation loc = findLocation(name);
|
||||
|
||||
if (loc != null) { // A sub tree node
|
||||
if (isPackages) {
|
||||
n = handlePackages(name, loc);
|
||||
} else { // modules sub tree
|
||||
n = handleModulesSubTree(name, loc);
|
||||
}
|
||||
} else { // Asking for a resource? /modules/java.base/java/lang/Object.class
|
||||
if (isModules) {
|
||||
n = handleResource(name);
|
||||
} else {
|
||||
// Possibly ask for /packages/java.lang/java.base
|
||||
// although /packages/java.base not created
|
||||
n = handleModuleLink(name);
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
synchronized Directory buildRootDirectory() {
|
||||
Directory root = rootDir; // volatile read
|
||||
if (root != null) {
|
||||
return root;
|
||||
}
|
||||
|
||||
root = newDirectory(null, "/");
|
||||
root.setIsRootDir();
|
||||
|
||||
// /packages dir
|
||||
packagesDir = newDirectory(root, "/packages");
|
||||
packagesDir.setIsPackagesDir();
|
||||
|
||||
// /modules dir
|
||||
modulesDir = newDirectory(root, "/modules");
|
||||
modulesDir.setIsModulesDir();
|
||||
|
||||
root.setCompleted(true);
|
||||
return rootDir = root;
|
||||
}
|
||||
|
||||
/**
|
||||
* To visit sub tree resources.
|
||||
*/
|
||||
interface LocationVisitor {
|
||||
void visit(ImageLocation loc);
|
||||
}
|
||||
|
||||
void visitLocation(ImageLocation loc, LocationVisitor visitor) {
|
||||
byte[] offsets = getResource(loc);
|
||||
ByteBuffer buffer = ByteBuffer.wrap(offsets);
|
||||
buffer.order(getByteOrder());
|
||||
IntBuffer intBuffer = buffer.asIntBuffer();
|
||||
for (int i = 0; i < offsets.length / SIZE_OF_OFFSET; i++) {
|
||||
int offset = intBuffer.get(i);
|
||||
ImageLocation pkgLoc = getLocation(offset);
|
||||
visitor.visit(pkgLoc);
|
||||
}
|
||||
}
|
||||
|
||||
void visitPackageLocation(ImageLocation loc) {
|
||||
// Retrieve package name
|
||||
String pkgName = getBaseExt(loc);
|
||||
// Content is array of offsets in Strings table
|
||||
byte[] stringsOffsets = getResource(loc);
|
||||
ByteBuffer buffer = ByteBuffer.wrap(stringsOffsets);
|
||||
buffer.order(getByteOrder());
|
||||
IntBuffer intBuffer = buffer.asIntBuffer();
|
||||
// For each module, create a link node.
|
||||
for (int i = 0; i < stringsOffsets.length / SIZE_OF_OFFSET; i++) {
|
||||
// skip empty state, useless.
|
||||
intBuffer.get(i);
|
||||
i++;
|
||||
int offset = intBuffer.get(i);
|
||||
String moduleName = getString(offset);
|
||||
Node targetNode = findNode("/modules/" + moduleName);
|
||||
if (targetNode != null) {
|
||||
String pkgDirName = packagesDir.getName() + "/" + pkgName;
|
||||
Directory pkgDir = (Directory) nodes.get(pkgDirName);
|
||||
newLinkNode(pkgDir, pkgDir.getName() + "/" + moduleName, targetNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Node handlePackages(String name, ImageLocation loc) {
|
||||
long size = loc.getUncompressedSize();
|
||||
Node n = null;
|
||||
// Only possiblities are /packages, /packages/package/module
|
||||
if (name.equals("/packages")) {
|
||||
visitLocation(loc, (childloc) -> {
|
||||
findNode(childloc.getFullName());
|
||||
});
|
||||
packagesDir.setCompleted(true);
|
||||
n = packagesDir;
|
||||
} else {
|
||||
if (size != 0) { // children are offsets to module in StringsTable
|
||||
String pkgName = getBaseExt(loc);
|
||||
Directory pkgDir = newDirectory(packagesDir, packagesDir.getName() + "/" + pkgName);
|
||||
visitPackageLocation(loc);
|
||||
pkgDir.setCompleted(true);
|
||||
n = pkgDir;
|
||||
} else { // Link to module
|
||||
String pkgName = loc.getParent();
|
||||
String modName = getBaseExt(loc);
|
||||
Node targetNode = findNode("/modules/" + modName);
|
||||
if (targetNode != null) {
|
||||
String pkgDirName = packagesDir.getName() + "/" + pkgName;
|
||||
Directory pkgDir = (Directory) nodes.get(pkgDirName);
|
||||
Node linkNode = newLinkNode(pkgDir, pkgDir.getName() + "/" + modName, targetNode);
|
||||
n = linkNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
// Asking for /packages/package/module although
|
||||
// /packages/<pkg>/ not yet created, need to create it
|
||||
// prior to return the link to module node.
|
||||
Node handleModuleLink(String name) {
|
||||
// eg: unresolved /packages/package/module
|
||||
// Build /packages/package node
|
||||
Node ret = null;
|
||||
String radical = "/packages/";
|
||||
String path = name;
|
||||
if (path.startsWith(radical)) {
|
||||
int start = radical.length();
|
||||
int pkgEnd = path.indexOf('/', start);
|
||||
if (pkgEnd != -1) {
|
||||
String pkg = path.substring(start, pkgEnd);
|
||||
String pkgPath = radical + pkg;
|
||||
Node n = findNode(pkgPath);
|
||||
// If not found means that this is a symbolic link such as:
|
||||
// /packages/java.util/java.base/java/util/Vector.class
|
||||
// and will be done by a retry of the filesystem
|
||||
for (Node child : n.getChildren()) {
|
||||
if (child.name.equals(name)) {
|
||||
ret = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Node handleModulesSubTree(String name, ImageLocation loc) {
|
||||
Node n;
|
||||
assert (name.equals(loc.getFullName()));
|
||||
Directory dir = makeDirectories(name);
|
||||
visitLocation(loc, (childloc) -> {
|
||||
String path = childloc.getFullName();
|
||||
if (path.startsWith("/modules")) { // a package
|
||||
makeDirectories(path);
|
||||
} else { // a resource
|
||||
makeDirectories(childloc.buildName(true, true, false));
|
||||
newResource(dir, childloc);
|
||||
}
|
||||
});
|
||||
dir.setCompleted(true);
|
||||
n = dir;
|
||||
return n;
|
||||
}
|
||||
|
||||
Node handleResource(String name) {
|
||||
Node n = null;
|
||||
if (!name.startsWith("/modules/")) {
|
||||
return null;
|
||||
}
|
||||
// Make sure that the thing that follows "/modules/" is a module name.
|
||||
int moduleEndIndex = name.indexOf('/', "/modules/".length());
|
||||
if (moduleEndIndex == -1) {
|
||||
return null;
|
||||
}
|
||||
ImageLocation moduleLoc = findLocation(name.substring(0, moduleEndIndex));
|
||||
if (moduleLoc == null || moduleLoc.getModuleOffset() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String locationPath = name.substring("/modules".length());
|
||||
ImageLocation resourceLoc = findLocation(locationPath);
|
||||
if (resourceLoc != null) {
|
||||
Directory dir = makeDirectories(resourceLoc.buildName(true, true, false));
|
||||
Resource res = newResource(dir, resourceLoc);
|
||||
n = res;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
String getBaseExt(ImageLocation loc) {
|
||||
String base = loc.getBase();
|
||||
String ext = loc.getExtension();
|
||||
if (ext != null && !ext.isEmpty()) {
|
||||
base = base + "." + ext;
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
synchronized Node findNode(String name) {
|
||||
buildRootDirectory();
|
||||
Node n = nodes.get(name);
|
||||
if (n == null || !n.isCompleted()) {
|
||||
n = buildNode(name);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file attributes of the image file.
|
||||
*/
|
||||
BasicFileAttributes imageFileAttributes() {
|
||||
BasicFileAttributes attrs = imageFileAttributes;
|
||||
if (attrs == null) {
|
||||
try {
|
||||
Path file = getImagePath();
|
||||
attrs = Files.readAttributes(file, BasicFileAttributes.class);
|
||||
} catch (IOException ioe) {
|
||||
throw new UncheckedIOException(ioe);
|
||||
}
|
||||
imageFileAttributes = attrs;
|
||||
}
|
||||
return attrs;
|
||||
}
|
||||
|
||||
Directory newDirectory(Directory parent, String name) {
|
||||
Directory dir = Directory.create(parent, name, imageFileAttributes());
|
||||
nodes.put(dir.getName(), dir);
|
||||
return dir;
|
||||
}
|
||||
|
||||
Resource newResource(Directory parent, ImageLocation loc) {
|
||||
Resource res = Resource.create(parent, loc, imageFileAttributes());
|
||||
nodes.put(res.getName(), res);
|
||||
return res;
|
||||
}
|
||||
|
||||
LinkNode newLinkNode(Directory dir, String name, Node link) {
|
||||
LinkNode linkNode = LinkNode.create(dir, name, link);
|
||||
nodes.put(linkNode.getName(), linkNode);
|
||||
return linkNode;
|
||||
}
|
||||
|
||||
Directory makeDirectories(String parent) {
|
||||
Directory last = rootDir;
|
||||
for (int offset = parent.indexOf('/', 1);
|
||||
offset != -1;
|
||||
offset = parent.indexOf('/', offset + 1)) {
|
||||
String dir = parent.substring(0, offset);
|
||||
last = makeDirectory(dir, last);
|
||||
}
|
||||
return makeDirectory(parent, last);
|
||||
|
||||
}
|
||||
|
||||
Directory makeDirectory(String dir, Directory last) {
|
||||
Directory nextDir = (Directory) nodes.get(dir);
|
||||
if (nextDir == null) {
|
||||
nextDir = newDirectory(last, dir);
|
||||
}
|
||||
return nextDir;
|
||||
}
|
||||
|
||||
byte[] getResource(Node node) throws IOException {
|
||||
if (node.isResource()) {
|
||||
return super.getResource(node.getLocation());
|
||||
}
|
||||
throw new IOException("Not a resource: " + node);
|
||||
}
|
||||
|
||||
byte[] getResource(Resource rs) throws IOException {
|
||||
return super.getResource(rs.getLocation());
|
||||
}
|
||||
}
|
||||
|
||||
// jimage file does not store directory structure. We build nodes
|
||||
// using the "path" strings found in the jimage file.
|
||||
// Node can be a directory or a resource
|
||||
public abstract static class Node {
|
||||
private static final int ROOT_DIR = 0b0000_0000_0000_0001;
|
||||
private static final int PACKAGES_DIR = 0b0000_0000_0000_0010;
|
||||
private static final int MODULES_DIR = 0b0000_0000_0000_0100;
|
||||
|
||||
private int flags;
|
||||
private final String name;
|
||||
private final BasicFileAttributes fileAttrs;
|
||||
private boolean completed;
|
||||
|
||||
protected Node(String name, BasicFileAttributes fileAttrs) {
|
||||
this.name = Objects.requireNonNull(name);
|
||||
this.fileAttrs = Objects.requireNonNull(fileAttrs);
|
||||
}
|
||||
|
||||
/**
|
||||
* A node is completed when all its direct children have been built.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isCompleted() {
|
||||
return completed;
|
||||
}
|
||||
|
||||
public void setCompleted(boolean completed) {
|
||||
this.completed = completed;
|
||||
}
|
||||
|
||||
public final void setIsRootDir() {
|
||||
flags |= ROOT_DIR;
|
||||
}
|
||||
|
||||
public final boolean isRootDir() {
|
||||
return (flags & ROOT_DIR) != 0;
|
||||
}
|
||||
|
||||
public final void setIsPackagesDir() {
|
||||
flags |= PACKAGES_DIR;
|
||||
}
|
||||
|
||||
public final boolean isPackagesDir() {
|
||||
return (flags & PACKAGES_DIR) != 0;
|
||||
}
|
||||
|
||||
public final void setIsModulesDir() {
|
||||
flags |= MODULES_DIR;
|
||||
}
|
||||
|
||||
public final boolean isModulesDir() {
|
||||
return (flags & MODULES_DIR) != 0;
|
||||
}
|
||||
|
||||
public final String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public final BasicFileAttributes getFileAttributes() {
|
||||
return fileAttrs;
|
||||
}
|
||||
|
||||
// resolve this Node (if this is a soft link, get underlying Node)
|
||||
public final Node resolveLink() {
|
||||
return resolveLink(false);
|
||||
}
|
||||
|
||||
public Node resolveLink(boolean recursive) {
|
||||
return this;
|
||||
}
|
||||
|
||||
// is this a soft link Node?
|
||||
public boolean isLink() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isDirectory() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<Node> getChildren() {
|
||||
throw new IllegalArgumentException("not a directory: " + getNameString());
|
||||
}
|
||||
|
||||
public boolean isResource() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public ImageLocation getLocation() {
|
||||
throw new IllegalArgumentException("not a resource: " + getNameString());
|
||||
}
|
||||
|
||||
public long size() {
|
||||
return 0L;
|
||||
}
|
||||
|
||||
public long compressedSize() {
|
||||
return 0L;
|
||||
}
|
||||
|
||||
public String extension() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public long contentOffset() {
|
||||
return 0L;
|
||||
}
|
||||
|
||||
public final FileTime creationTime() {
|
||||
return fileAttrs.creationTime();
|
||||
}
|
||||
|
||||
public final FileTime lastAccessTime() {
|
||||
return fileAttrs.lastAccessTime();
|
||||
}
|
||||
|
||||
public final FileTime lastModifiedTime() {
|
||||
return fileAttrs.lastModifiedTime();
|
||||
}
|
||||
|
||||
public final String getNameString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String toString() {
|
||||
return getNameString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return name.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (other instanceof Node) {
|
||||
return name.equals(((Node) other).name);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// directory node - directory has full path name without '/' at end.
|
||||
static final class Directory extends Node {
|
||||
private final List<Node> children;
|
||||
|
||||
private Directory(String name, BasicFileAttributes fileAttrs) {
|
||||
super(name, fileAttrs);
|
||||
children = new ArrayList<>();
|
||||
}
|
||||
|
||||
static Directory create(Directory parent, String name, BasicFileAttributes fileAttrs) {
|
||||
Directory d = new Directory(name, fileAttrs);
|
||||
if (parent != null) {
|
||||
parent.addChild(d);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirectory() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Node> getChildren() {
|
||||
return Collections.unmodifiableList(children);
|
||||
}
|
||||
|
||||
void addChild(Node node) {
|
||||
children.add(node);
|
||||
}
|
||||
|
||||
public void walk(Consumer<? super Node> consumer) {
|
||||
consumer.accept(this);
|
||||
for (Node child : children) {
|
||||
if (child.isDirectory()) {
|
||||
((Directory)child).walk(consumer);
|
||||
} else {
|
||||
consumer.accept(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// "resource" is .class or any other resource (compressed/uncompressed) in a jimage.
|
||||
// full path of the resource is the "name" of the resource.
|
||||
static class Resource extends Node {
|
||||
private final ImageLocation loc;
|
||||
|
||||
private Resource(ImageLocation loc, BasicFileAttributes fileAttrs) {
|
||||
super(loc.getFullName(true), fileAttrs);
|
||||
this.loc = loc;
|
||||
}
|
||||
|
||||
static Resource create(Directory parent, ImageLocation loc, BasicFileAttributes fileAttrs) {
|
||||
Resource rs = new Resource(loc, fileAttrs);
|
||||
parent.addChild(rs);
|
||||
return rs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCompleted() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isResource() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageLocation getLocation() {
|
||||
return loc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long size() {
|
||||
return loc.getUncompressedSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long compressedSize() {
|
||||
return loc.getCompressedSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String extension() {
|
||||
return loc.getExtension();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long contentOffset() {
|
||||
return loc.getContentOffset();
|
||||
}
|
||||
}
|
||||
|
||||
// represents a soft link to another Node
|
||||
static class LinkNode extends Node {
|
||||
private final Node link;
|
||||
|
||||
private LinkNode(String name, Node link) {
|
||||
super(name, link.getFileAttributes());
|
||||
this.link = link;
|
||||
}
|
||||
|
||||
static LinkNode create(Directory parent, String name, Node link) {
|
||||
LinkNode ln = new LinkNode(name, link);
|
||||
parent.addChild(ln);
|
||||
return ln;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCompleted() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node resolveLink(boolean recursive) {
|
||||
return (recursive && link instanceof LinkNode) ? ((LinkNode)link).resolveLink(true) : link;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLink() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javac.internal.jimage;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Factory to get ImageReader
|
||||
*
|
||||
* @implNote This class needs to maintain JDK 8 source compatibility.
|
||||
*
|
||||
* It is used internally in the JDK to implement jimage/jrtfs access,
|
||||
* but also compiled and delivered as part of the jrtfs.jar to support access
|
||||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
public class ImageReaderFactory {
|
||||
private ImageReaderFactory() {}
|
||||
|
||||
// AndroidIDE changed: Allow overriding java home.
|
||||
private static final String JAVA_HOME = com.itsaky.androidide.config.JavacConfigProvider.getJavaHome();
|
||||
private static final Path BOOT_MODULES_JIMAGE =
|
||||
Paths.get(JAVA_HOME, "lib", "modules");
|
||||
|
||||
private static final Map<Path, ImageReader> readers = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Returns an {@code ImageReader} to read from the given image file
|
||||
*/
|
||||
public static ImageReader get(Path jimage) throws IOException {
|
||||
Objects.requireNonNull(jimage);
|
||||
try {
|
||||
return readers.computeIfAbsent(jimage, OPENER);
|
||||
} catch (UncheckedIOException io) {
|
||||
throw io.getCause();
|
||||
}
|
||||
}
|
||||
|
||||
private static Function<Path, ImageReader> OPENER = new Function<Path, ImageReader>() {
|
||||
public ImageReader apply(Path path) {
|
||||
try {
|
||||
return ImageReader.open(path);
|
||||
} catch (IOException io) {
|
||||
throw new UncheckedIOException(io);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the {@code ImageReader} to read the image file in this
|
||||
* run-time image.
|
||||
*
|
||||
* @throws UncheckedIOException if an I/O error occurs
|
||||
*/
|
||||
public static ImageReader getImageReader() {
|
||||
try {
|
||||
return get(BOOT_MODULES_JIMAGE);
|
||||
} catch (IOException ioe) {
|
||||
throw new UncheckedIOException(ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javac.internal.jimage;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @implNote This class needs to maintain JDK 8 source compatibility.
|
||||
*
|
||||
* It is used internally in the JDK to implement jimage/jrtfs access,
|
||||
* but also compiled and delivered as part of the jrtfs.jar to support access
|
||||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
public class ImageStream {
|
||||
private ByteBuffer buffer;
|
||||
|
||||
public ImageStream() {
|
||||
this(1024, ByteOrder.nativeOrder());
|
||||
}
|
||||
|
||||
public ImageStream(int size) {
|
||||
this(size, ByteOrder.nativeOrder());
|
||||
}
|
||||
|
||||
public ImageStream(byte[] bytes) {
|
||||
this(bytes, ByteOrder.nativeOrder());
|
||||
}
|
||||
|
||||
public ImageStream(ByteOrder byteOrder) {
|
||||
this(1024, byteOrder);
|
||||
}
|
||||
|
||||
public ImageStream(int size, ByteOrder byteOrder) {
|
||||
buffer = ByteBuffer.allocate(size);
|
||||
buffer.order(Objects.requireNonNull(byteOrder));
|
||||
}
|
||||
|
||||
public ImageStream(byte[] bytes, ByteOrder byteOrder) {
|
||||
buffer = ByteBuffer.wrap(Objects.requireNonNull(bytes));
|
||||
buffer.order(Objects.requireNonNull(byteOrder));
|
||||
}
|
||||
|
||||
public ImageStream(ByteBuffer buffer) {
|
||||
this.buffer = Objects.requireNonNull(buffer);
|
||||
}
|
||||
|
||||
public ImageStream align(int alignment) {
|
||||
int padding = (getSize() - 1) & ((1 << alignment) - 1);
|
||||
|
||||
for (int i = 0; i < padding; i++) {
|
||||
put((byte)0);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public void ensure(int needs) {
|
||||
if (needs < 0) {
|
||||
throw new IndexOutOfBoundsException("Bad value: " + needs);
|
||||
}
|
||||
|
||||
if (needs > buffer.remaining()) {
|
||||
byte[] bytes = buffer.array();
|
||||
ByteOrder byteOrder = buffer.order();
|
||||
int position = buffer.position();
|
||||
int newSize = needs <= bytes.length ? bytes.length << 1 : position + needs;
|
||||
buffer = ByteBuffer.allocate(newSize);
|
||||
buffer.order(byteOrder);
|
||||
buffer.put(bytes, 0, position);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasByte() {
|
||||
return buffer.remaining() != 0;
|
||||
}
|
||||
|
||||
public boolean hasBytes(int needs) {
|
||||
return needs <= buffer.remaining();
|
||||
}
|
||||
|
||||
public void skip(int n) {
|
||||
if (n < 0) {
|
||||
throw new IndexOutOfBoundsException("skip value = " + n);
|
||||
}
|
||||
|
||||
buffer.position(buffer.position() + n);
|
||||
}
|
||||
|
||||
public int get() {
|
||||
return buffer.get() & 0xFF;
|
||||
}
|
||||
|
||||
public void get(byte bytes[], int offset, int size) {
|
||||
buffer.get(bytes, offset, size);
|
||||
}
|
||||
|
||||
public int getShort() {
|
||||
return buffer.getShort();
|
||||
}
|
||||
|
||||
public int getInt() {
|
||||
return buffer.getInt();
|
||||
}
|
||||
|
||||
public long getLong() {
|
||||
return buffer.getLong();
|
||||
}
|
||||
|
||||
public ImageStream put(byte byt) {
|
||||
ensure(1);
|
||||
buffer.put(byt);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ImageStream put(int byt) {
|
||||
return put((byte)byt);
|
||||
}
|
||||
|
||||
public ImageStream put(byte bytes[], int offset, int size) {
|
||||
ensure(size);
|
||||
buffer.put(bytes, offset, size);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ImageStream put(ImageStream stream) {
|
||||
put(stream.buffer.array(), 0, stream.buffer.position());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ImageStream putShort(short value) {
|
||||
ensure(2);
|
||||
buffer.putShort(value);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ImageStream putShort(int value) {
|
||||
return putShort((short)value);
|
||||
}
|
||||
|
||||
public ImageStream putInt(int value) {
|
||||
ensure(4);
|
||||
buffer.putInt(value);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ImageStream putLong(long value) {
|
||||
ensure(8);
|
||||
buffer.putLong(value);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ByteBuffer getBuffer() {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public int getPosition() {
|
||||
return buffer.position();
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return buffer.position();
|
||||
}
|
||||
|
||||
public byte[] getBytes() {
|
||||
return buffer.array();
|
||||
}
|
||||
|
||||
public void setPosition(int offset) {
|
||||
buffer.position(offset);
|
||||
}
|
||||
|
||||
public byte[] toArray() {
|
||||
return Arrays.copyOf(buffer.array(), buffer.position());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javac.internal.jimage;
|
||||
|
||||
/**
|
||||
* @implNote This interface needs to maintain JDK 8 source compatibility.
|
||||
*
|
||||
* It is used internally in the JDK to implement jimage/jrtfs access,
|
||||
* but also compiled and delivered as part of the jrtfs.jar to support access
|
||||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
public interface ImageStrings {
|
||||
String get(int offset);
|
||||
|
||||
int add(final String string);
|
||||
|
||||
/**
|
||||
* If there's a string at {@code offset} matching in full a substring of
|
||||
* {@code string} starting at {@code stringOffset}, return the length
|
||||
* of that string. Otherwise returns -1. Optional operation.
|
||||
*/
|
||||
default int match(int offset, String string, int stringOffset) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
||||
+387
@@ -0,0 +1,387 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javac.internal.jimage;
|
||||
|
||||
import java.io.UTFDataFormatException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @implNote This class needs to maintain JDK 8 source compatibility.
|
||||
*
|
||||
* It is used internally in the JDK to implement jimage/jrtfs access,
|
||||
* but also compiled and delivered as part of the jrtfs.jar to support access
|
||||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
public class ImageStringsReader implements ImageStrings {
|
||||
public static final int HASH_MULTIPLIER = 0x01000193;
|
||||
public static final int POSITIVE_MASK = 0x7FFFFFFF;
|
||||
|
||||
private final BasicImageReader reader;
|
||||
|
||||
ImageStringsReader(BasicImageReader reader) {
|
||||
this.reader = Objects.requireNonNull(reader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(int offset) {
|
||||
return reader.getString(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int match(int offset, String string, int stringOffset) {
|
||||
return reader.match(offset, string, stringOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int add(final String string) {
|
||||
throw new InternalError("Can not add strings at runtime");
|
||||
}
|
||||
|
||||
public static int hashCode(String s) {
|
||||
return hashCode(s, HASH_MULTIPLIER);
|
||||
}
|
||||
|
||||
public static int hashCode(String s, int seed) {
|
||||
return unmaskedHashCode(s, seed) & POSITIVE_MASK;
|
||||
}
|
||||
|
||||
public static int hashCode(String module, String name) {
|
||||
return hashCode(module, name, HASH_MULTIPLIER);
|
||||
}
|
||||
|
||||
public static int hashCode(String module, String name, int seed) {
|
||||
seed = (seed * HASH_MULTIPLIER) ^ ('/');
|
||||
seed = unmaskedHashCode(module, seed);
|
||||
seed = (seed * HASH_MULTIPLIER) ^ ('/');
|
||||
seed = unmaskedHashCode(name, seed);
|
||||
return seed & POSITIVE_MASK;
|
||||
}
|
||||
|
||||
public static int unmaskedHashCode(String s, int seed) {
|
||||
int slen = s.length();
|
||||
byte[] buffer = null;
|
||||
|
||||
for (int i = 0; i < slen; i++) {
|
||||
int uch = s.charAt(i);
|
||||
|
||||
if ((uch & ~0x7F) != 0) {
|
||||
if (buffer == null) {
|
||||
buffer = new byte[8];
|
||||
}
|
||||
int mask = ~0x3F;
|
||||
int n = 0;
|
||||
|
||||
do {
|
||||
buffer[n++] = (byte)(0x80 | (uch & 0x3F));
|
||||
uch >>= 6;
|
||||
mask >>= 1;
|
||||
} while ((uch & mask) != 0);
|
||||
|
||||
buffer[n] = (byte)((mask << 1) | uch);
|
||||
|
||||
do {
|
||||
seed = (seed * HASH_MULTIPLIER) ^ (buffer[n--] & 0xFF);
|
||||
} while (0 <= n);
|
||||
} else if (uch == 0) {
|
||||
seed = (seed * HASH_MULTIPLIER) ^ (0xC0);
|
||||
seed = (seed * HASH_MULTIPLIER) ^ (0x80);
|
||||
} else {
|
||||
seed = (seed * HASH_MULTIPLIER) ^ (uch);
|
||||
}
|
||||
}
|
||||
return seed;
|
||||
}
|
||||
|
||||
static int charsFromMUTF8Length(byte[] bytes, int offset, int count) {
|
||||
int length = 0;
|
||||
|
||||
for (int i = offset; i < offset + count; i++) {
|
||||
byte ch = bytes[i];
|
||||
|
||||
if (ch == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((ch & 0xC0) != 0x80) {
|
||||
length++;
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
static void charsFromMUTF8(char[] chars, byte[] bytes, int offset, int count) throws UTFDataFormatException {
|
||||
int j = 0;
|
||||
|
||||
for (int i = offset; i < offset + count; i++) {
|
||||
byte ch = bytes[i];
|
||||
|
||||
if (ch == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
boolean is_unicode = (ch & 0x80) != 0;
|
||||
int uch = ch & 0x7F;
|
||||
|
||||
if (is_unicode) {
|
||||
int mask = 0x40;
|
||||
|
||||
while ((uch & mask) != 0) {
|
||||
ch = bytes[++i];
|
||||
|
||||
if ((ch & 0xC0) != 0x80) {
|
||||
throw new UTFDataFormatException("bad continuation 0x" + Integer.toHexString(ch));
|
||||
}
|
||||
|
||||
uch = ((uch & ~mask) << 6) | (ch & 0x3F);
|
||||
mask <<= 6 - 1;
|
||||
}
|
||||
|
||||
if ((uch & 0xFFFF) != uch) {
|
||||
throw new UTFDataFormatException("character out of range \\u" + Integer.toHexString(uch));
|
||||
}
|
||||
}
|
||||
|
||||
chars[j++] = (char)uch;
|
||||
}
|
||||
}
|
||||
|
||||
public static String stringFromMUTF8(byte[] bytes, int offset, int count) {
|
||||
int length = charsFromMUTF8Length(bytes, offset, count);
|
||||
char[] chars = new char[length];
|
||||
|
||||
try {
|
||||
charsFromMUTF8(chars, bytes, offset, count);
|
||||
} catch (UTFDataFormatException ex) {
|
||||
throw new InternalError("Attempt to convert non modified UTF-8 byte sequence", ex);
|
||||
}
|
||||
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
public static String stringFromMUTF8(byte[] bytes) {
|
||||
return stringFromMUTF8(bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the number of characters in the String present at the
|
||||
* specified offset. As an optimization, the length returned will
|
||||
* be positive if the characters are all ASCII, and negative otherwise.
|
||||
*/
|
||||
private static int charsFromByteBufferLength(ByteBuffer buffer, int offset) {
|
||||
int length = 0;
|
||||
|
||||
int limit = buffer.limit();
|
||||
boolean asciiOnly = true;
|
||||
while (offset < limit) {
|
||||
byte ch = buffer.get(offset++);
|
||||
|
||||
if (ch < 0) {
|
||||
asciiOnly = false;
|
||||
} else if (ch == 0) {
|
||||
return asciiOnly ? length : -length;
|
||||
}
|
||||
|
||||
if ((ch & 0xC0) != 0x80) {
|
||||
length++;
|
||||
}
|
||||
}
|
||||
throw new InternalError("No terminating zero byte for modified UTF-8 byte sequence");
|
||||
}
|
||||
|
||||
private static void charsFromByteBuffer(char[] chars, ByteBuffer buffer, int offset) {
|
||||
int j = 0;
|
||||
|
||||
int limit = buffer.limit();
|
||||
while (offset < limit) {
|
||||
byte ch = buffer.get(offset++);
|
||||
|
||||
if (ch == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean is_unicode = (ch & 0x80) != 0;
|
||||
int uch = ch & 0x7F;
|
||||
|
||||
if (is_unicode) {
|
||||
int mask = 0x40;
|
||||
|
||||
while ((uch & mask) != 0) {
|
||||
ch = buffer.get(offset++);
|
||||
|
||||
if ((ch & 0xC0) != 0x80) {
|
||||
throw new InternalError("Bad continuation in " +
|
||||
"modified UTF-8 byte sequence: " + ch);
|
||||
}
|
||||
|
||||
uch = ((uch & ~mask) << 6) | (ch & 0x3F);
|
||||
mask <<= 6 - 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((uch & 0xFFFF) != uch) {
|
||||
throw new InternalError("UTF-32 char in modified UTF-8 " +
|
||||
"byte sequence: " + uch);
|
||||
}
|
||||
|
||||
chars[j++] = (char)uch;
|
||||
}
|
||||
|
||||
throw new InternalError("No terminating zero byte for modified UTF-8 byte sequence");
|
||||
}
|
||||
|
||||
public static String stringFromByteBuffer(ByteBuffer buffer) {
|
||||
return stringFromByteBuffer(buffer, 0);
|
||||
}
|
||||
|
||||
/* package-private */
|
||||
static String stringFromByteBuffer(ByteBuffer buffer, int offset) {
|
||||
int length = charsFromByteBufferLength(buffer, offset);
|
||||
if (length > 0) {
|
||||
byte[] asciiBytes = new byte[length];
|
||||
// Ideally we could use buffer.get(offset, asciiBytes, 0, length)
|
||||
// here, but that was introduced in JDK 13
|
||||
for (int i = 0; i < length; i++) {
|
||||
asciiBytes[i] = buffer.get(offset++);
|
||||
}
|
||||
return new String(asciiBytes, StandardCharsets.US_ASCII);
|
||||
}
|
||||
char[] chars = new char[-length];
|
||||
charsFromByteBuffer(chars, buffer, offset);
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
/* package-private */
|
||||
static int stringFromByteBufferMatches(ByteBuffer buffer, int offset, String string, int stringOffset) {
|
||||
// ASCII fast-path
|
||||
int limit = buffer.limit();
|
||||
int current = offset;
|
||||
int slen = string.length();
|
||||
while (current < limit) {
|
||||
byte ch = buffer.get(current);
|
||||
if (ch <= 0) {
|
||||
if (ch == 0) {
|
||||
// Match
|
||||
return current - offset;
|
||||
}
|
||||
// non-ASCII byte, run slow-path from current offset
|
||||
break;
|
||||
}
|
||||
if (slen <= stringOffset || string.charAt(stringOffset) != (char)ch) {
|
||||
// No match
|
||||
return -1;
|
||||
}
|
||||
stringOffset++;
|
||||
current++;
|
||||
}
|
||||
// invariant: remainder of the string starting at current is non-ASCII,
|
||||
// so return value from charsFromByteBufferLength will be negative
|
||||
int length = -charsFromByteBufferLength(buffer, current);
|
||||
char[] chars = new char[length];
|
||||
charsFromByteBuffer(chars, buffer, current);
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (string.charAt(stringOffset++) != chars[i]) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
static int mutf8FromStringLength(String s) {
|
||||
int length = 0;
|
||||
int slen = s.length();
|
||||
|
||||
for (int i = 0; i < slen; i++) {
|
||||
char ch = s.charAt(i);
|
||||
int uch = ch & 0xFFFF;
|
||||
|
||||
if ((uch & ~0x7F) != 0) {
|
||||
int mask = ~0x3F;
|
||||
int n = 0;
|
||||
|
||||
do {
|
||||
n++;
|
||||
uch >>= 6;
|
||||
mask >>= 1;
|
||||
} while ((uch & mask) != 0);
|
||||
|
||||
length += n + 1;
|
||||
} else if (uch == 0) {
|
||||
length += 2;
|
||||
} else {
|
||||
length++;
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
static void mutf8FromString(byte[] bytes, int offset, String s) {
|
||||
int j = offset;
|
||||
byte[] buffer = null;
|
||||
int slen = s.length();
|
||||
|
||||
for (int i = 0; i < slen; i++) {
|
||||
char ch = s.charAt(i);
|
||||
int uch = ch & 0xFFFF;
|
||||
|
||||
if ((uch & ~0x7F) != 0) {
|
||||
if (buffer == null) {
|
||||
buffer = new byte[8];
|
||||
}
|
||||
int mask = ~0x3F;
|
||||
int n = 0;
|
||||
|
||||
do {
|
||||
buffer[n++] = (byte)(0x80 | (uch & 0x3F));
|
||||
uch >>= 6;
|
||||
mask >>= 1;
|
||||
} while ((uch & mask) != 0);
|
||||
|
||||
buffer[n] = (byte)((mask << 1) | uch);
|
||||
|
||||
do {
|
||||
bytes[j++] = buffer[n--];
|
||||
} while (0 <= n);
|
||||
} else if (uch == 0) {
|
||||
bytes[j++] = (byte)0xC0;
|
||||
bytes[j++] = (byte)0x80;
|
||||
} else {
|
||||
bytes[j++] = (byte)uch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] mutf8FromString(String string) {
|
||||
int length = mutf8FromStringLength(string);
|
||||
byte[] bytes = new byte[length];
|
||||
mutf8FromString(bytes, 0, string);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javac.internal.jimage;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* @implNote This class needs to maintain JDK 8 source compatibility.
|
||||
*
|
||||
* It is used internally in the JDK to implement jimage/jrtfs access,
|
||||
* but also compiled and delivered as part of the jrtfs.jar to support access
|
||||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
class NativeImageBuffer {
|
||||
static {
|
||||
java.security.AccessController.doPrivileged(
|
||||
new java.security.PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
System.loadLibrary("jimage");
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
native static ByteBuffer getNativeMap(String imagePath);
|
||||
}
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javac.internal.jimage.decompressor;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* Index compressor. Use the minimal amount of bytes required to store
|
||||
* an integer.
|
||||
*
|
||||
* @implNote This class needs to maintain JDK 8 source compatibility.
|
||||
*
|
||||
* It is used internally in the JDK to implement jimage/jrtfs access,
|
||||
* but also compiled and delivered as part of the jrtfs.jar to support access
|
||||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
public class CompressIndexes {
|
||||
private static final int COMPRESSED_FLAG = 1 << (Byte.SIZE - 1);
|
||||
private static final int HEADER_WIDTH = 3;
|
||||
private static final int HEADER_SHIFT = Byte.SIZE - HEADER_WIDTH;
|
||||
|
||||
public static List<Integer> decompressFlow(byte[] values) {
|
||||
List<Integer> lst = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < values.length; i += getHeaderLength(values[i])) {
|
||||
int decompressed = decompress(values, i);
|
||||
lst.add(decompressed);
|
||||
}
|
||||
|
||||
return lst;
|
||||
}
|
||||
|
||||
public static int readInt(DataInputStream cr) throws IOException {
|
||||
// Get header byte.
|
||||
byte header = cr.readByte();
|
||||
// Determine size.
|
||||
int size = getHeaderLength(header);
|
||||
// Prepare result.
|
||||
int result = getHeaderValue(header);
|
||||
|
||||
// For each value byte
|
||||
for (int i = 1; i < size; i++) {
|
||||
// Merge byte value.
|
||||
result <<= Byte.SIZE;
|
||||
result |= cr.readByte() & 0xFF;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean isCompressed(byte b) {
|
||||
return (b & COMPRESSED_FLAG) != 0;
|
||||
}
|
||||
|
||||
private static int getHeaderLength(byte b) {
|
||||
return isCompressed(b) ? (b >> HEADER_SHIFT) & 3 : Integer.BYTES;
|
||||
}
|
||||
|
||||
private static int getHeaderValue(byte b) {
|
||||
return isCompressed(b) ? b & (1 << HEADER_SHIFT) - 1 : b;
|
||||
}
|
||||
|
||||
public static int decompress(byte[] value, int offset) {
|
||||
// Get header byte.
|
||||
byte header = value[offset];
|
||||
// Determine size.
|
||||
int size = getHeaderLength(header);
|
||||
// Prepare result.
|
||||
int result = getHeaderValue(header);
|
||||
|
||||
// For each value byte
|
||||
for (int i = 1; i < size; i++) {
|
||||
// Merge byte value.
|
||||
result <<= Byte.SIZE;
|
||||
result |= value[offset + i] & 0xFF;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static byte[] compress(int value) {
|
||||
// Only positive values are supported.
|
||||
if (value < 0) {
|
||||
throw new IllegalArgumentException("value < 0");
|
||||
}
|
||||
|
||||
// Determine number of significant digits.
|
||||
int width = 32 - Integer.numberOfLeadingZeros(value);
|
||||
// Determine number of byte to represent. Allow for header if
|
||||
// compressed.
|
||||
int size = Math.min(((width + HEADER_WIDTH - 1) >> 3) + 1, Integer.BYTES);
|
||||
|
||||
// Allocate result buffer.
|
||||
byte[] result = new byte[size];
|
||||
|
||||
// Insert significant bytes in result.
|
||||
for (int i = 0; i < size; i++) {
|
||||
result[i] = (byte)(value >> ((size - i - 1) * Byte.SIZE));
|
||||
}
|
||||
|
||||
// If compressed, mark and insert size.
|
||||
if (size < Integer.BYTES) {
|
||||
result[0] |= (byte)(COMPRESSED_FLAG | (size << HEADER_SHIFT));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javac.internal.jimage.decompressor;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Objects;
|
||||
|
||||
import javac.internal.jimage.decompressor.ResourceDecompressor.StringsProvider;
|
||||
|
||||
/**
|
||||
*
|
||||
* A resource header for compressed resource. This class is handled internally,
|
||||
* you don't have to add header to the resource, headers are added automatically
|
||||
* for compressed resources.
|
||||
*
|
||||
* @implNote This class needs to maintain JDK 8 source compatibility.
|
||||
*
|
||||
* It is used internally in the JDK to implement jimage/jrtfs access,
|
||||
* but also compiled and delivered as part of the jrtfs.jar to support access
|
||||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
public final class CompressedResourceHeader {
|
||||
|
||||
private static final int SIZE = 29;
|
||||
public static final int MAGIC = 0xCAFEFAFA;
|
||||
private final long uncompressedSize;
|
||||
private final long compressedSize;
|
||||
private final int decompressorNameOffset;
|
||||
private final int contentOffset;
|
||||
private final boolean isTerminal;
|
||||
|
||||
public CompressedResourceHeader(long compressedSize,
|
||||
long uncompressedSize, int decompressorNameOffset, int contentOffset,
|
||||
boolean isTerminal) {
|
||||
this.compressedSize = compressedSize;
|
||||
this.uncompressedSize = uncompressedSize;
|
||||
this.decompressorNameOffset = decompressorNameOffset;
|
||||
this.contentOffset = contentOffset;
|
||||
this.isTerminal = isTerminal;
|
||||
}
|
||||
|
||||
public boolean isTerminal() {
|
||||
return isTerminal;
|
||||
}
|
||||
|
||||
public int getDecompressorNameOffset() {
|
||||
return decompressorNameOffset;
|
||||
}
|
||||
|
||||
public int getContentOffset() {
|
||||
return contentOffset;
|
||||
}
|
||||
|
||||
public String getStoredContent(StringsProvider provider) {
|
||||
Objects.requireNonNull(provider);
|
||||
if(contentOffset == -1) {
|
||||
return null;
|
||||
}
|
||||
return provider.getString(contentOffset);
|
||||
}
|
||||
|
||||
public long getUncompressedSize() {
|
||||
return uncompressedSize;
|
||||
}
|
||||
|
||||
public long getResourceSize() {
|
||||
return compressedSize;
|
||||
}
|
||||
|
||||
public byte[] getBytes(ByteOrder order) {
|
||||
Objects.requireNonNull(order);
|
||||
ByteBuffer buffer = ByteBuffer.allocate(SIZE);
|
||||
buffer.order(order);
|
||||
buffer.putInt(MAGIC);
|
||||
buffer.putLong(compressedSize);
|
||||
buffer.putLong(uncompressedSize);
|
||||
buffer.putInt(decompressorNameOffset);
|
||||
buffer.putInt(contentOffset);
|
||||
buffer.put(isTerminal ? (byte)1 : (byte)0);
|
||||
return buffer.array();
|
||||
}
|
||||
|
||||
public static int getSize() {
|
||||
return SIZE;
|
||||
}
|
||||
|
||||
public static CompressedResourceHeader readFromResource(ByteOrder order,
|
||||
byte[] resource) {
|
||||
Objects.requireNonNull(order);
|
||||
Objects.requireNonNull(resource);
|
||||
if (resource.length < getSize()) {
|
||||
return null;
|
||||
}
|
||||
ByteBuffer buffer = ByteBuffer.wrap(resource, 0, SIZE);
|
||||
buffer.order(order);
|
||||
int magic = buffer.getInt();
|
||||
if(magic != MAGIC) {
|
||||
return null;
|
||||
}
|
||||
long size = buffer.getLong();
|
||||
long uncompressedSize = buffer.getLong();
|
||||
int decompressorNameOffset = buffer.getInt();
|
||||
int contentIndex = buffer.getInt();
|
||||
byte isTerminal = buffer.get();
|
||||
return new CompressedResourceHeader(size, uncompressedSize,
|
||||
decompressorNameOffset, contentIndex, isTerminal == 1);
|
||||
}
|
||||
}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javac.internal.jimage.decompressor;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
import javac.internal.jimage.decompressor.ResourceDecompressor.StringsProvider;
|
||||
|
||||
/**
|
||||
* Entry point to decompress resources.
|
||||
*
|
||||
* @implNote This class needs to maintain JDK 8 source compatibility.
|
||||
*
|
||||
* It is used internally in the JDK to implement jimage/jrtfs access,
|
||||
* but also compiled and delivered as part of the jrtfs.jar to support access
|
||||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
public final class Decompressor {
|
||||
|
||||
private final Map<Integer, ResourceDecompressor> pluginsCache = new HashMap<>();
|
||||
|
||||
public Decompressor() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Decompress a resource.
|
||||
* @param order Byte order.
|
||||
* @param provider Strings provider
|
||||
* @param content The resource content to uncompress.
|
||||
* @return A fully uncompressed resource.
|
||||
* @throws IOException
|
||||
*/
|
||||
public byte[] decompressResource(ByteOrder order, StringsProvider provider,
|
||||
byte[] content) throws IOException {
|
||||
Objects.requireNonNull(order);
|
||||
Objects.requireNonNull(provider);
|
||||
Objects.requireNonNull(content);
|
||||
CompressedResourceHeader header;
|
||||
do {
|
||||
header = CompressedResourceHeader.readFromResource(order, content);
|
||||
if (header != null) {
|
||||
ResourceDecompressor decompressor =
|
||||
pluginsCache.get(header.getDecompressorNameOffset());
|
||||
if (decompressor == null) {
|
||||
String pluginName =
|
||||
provider.getString(header.getDecompressorNameOffset());
|
||||
if (pluginName == null) {
|
||||
throw new IOException("Plugin name not found");
|
||||
}
|
||||
String storedContent = header.getStoredContent(provider);
|
||||
Properties props = new Properties();
|
||||
if (storedContent != null) {
|
||||
try (ByteArrayInputStream stream
|
||||
= new ByteArrayInputStream(storedContent.
|
||||
getBytes(StandardCharsets.UTF_8));) {
|
||||
props.loadFromXML(stream);
|
||||
}
|
||||
}
|
||||
decompressor = ResourceDecompressorRepository.
|
||||
newResourceDecompressor(props, pluginName);
|
||||
if (decompressor == null) {
|
||||
throw new IOException("Plugin not found: " + pluginName);
|
||||
}
|
||||
|
||||
pluginsCache.put(header.getDecompressorNameOffset(), decompressor);
|
||||
}
|
||||
try {
|
||||
content = decompressor.decompress(provider, content,
|
||||
CompressedResourceHeader.getSize(), header.getUncompressedSize());
|
||||
} catch (Exception ex) {
|
||||
throw new IOException(ex);
|
||||
}
|
||||
}
|
||||
} while (header != null);
|
||||
return content;
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javac.internal.jimage.decompressor;
|
||||
|
||||
/**
|
||||
*
|
||||
* JLink Image Decompressor.
|
||||
*
|
||||
* @implNote This class needs to maintain JDK 8 source compatibility.
|
||||
*
|
||||
* It is used internally in the JDK to implement jimage/jrtfs access,
|
||||
* but also compiled and delivered as part of the jrtfs.jar to support access
|
||||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
public interface ResourceDecompressor {
|
||||
|
||||
public interface StringsProvider {
|
||||
public String getString(int offset);
|
||||
}
|
||||
/**
|
||||
* Decompressor unique name.
|
||||
* @return The decompressor name.
|
||||
*/
|
||||
public String getName();
|
||||
|
||||
/**
|
||||
* Decompress a resource.
|
||||
* @param strings The String provider
|
||||
* @param content The resource content
|
||||
* @param offset Resource content offset
|
||||
* @param originalSize Uncompressed size
|
||||
* @return Uncompressed resource
|
||||
* @throws Exception
|
||||
*/
|
||||
public byte[] decompress(StringsProvider strings, byte[] content, int offset,
|
||||
long originalSize) throws Exception;
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javac.internal.jimage.decompressor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
*
|
||||
* JLink Resource Decompressor factory
|
||||
*
|
||||
* @implNote This class needs to maintain JDK 8 source compatibility.
|
||||
*
|
||||
* It is used internally in the JDK to implement jimage/jrtfs access,
|
||||
* but also compiled and delivered as part of the jrtfs.jar to support access
|
||||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
public abstract class ResourceDecompressorFactory {
|
||||
private final String name;
|
||||
|
||||
protected ResourceDecompressorFactory(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Factory name.
|
||||
* @return The name.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* To build a new decompressor.
|
||||
* @param properties Contains configuration.
|
||||
* @return A new decompressor.
|
||||
* @throws IOException
|
||||
*/
|
||||
public abstract ResourceDecompressor newDecompressor(Properties properties)
|
||||
throws IOException;
|
||||
|
||||
}
|
||||
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javac.internal.jimage.decompressor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
*
|
||||
* JLink Decompressors. All decompressors must be registered in the static
|
||||
* initializer of this class.
|
||||
*
|
||||
* @implNote This class needs to maintain JDK 8 source compatibility.
|
||||
*
|
||||
* It is used internally in the JDK to implement jimage/jrtfs access,
|
||||
* but also compiled and delivered as part of the jrtfs.jar to support access
|
||||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
public final class ResourceDecompressorRepository {
|
||||
|
||||
private ResourceDecompressorRepository() {
|
||||
}
|
||||
|
||||
private static final Map<String, ResourceDecompressorFactory> factories = new HashMap<>();
|
||||
|
||||
static {
|
||||
registerReaderProvider(new ZipDecompressorFactory());
|
||||
registerReaderProvider(new StringSharingDecompressorFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a new decompressor for the passed name.
|
||||
* @param properties Contains plugin configuration.
|
||||
* @param name The plugin name to build.
|
||||
* @return A decompressor or null if not found
|
||||
* @throws IOException
|
||||
*/
|
||||
public static ResourceDecompressor newResourceDecompressor(Properties properties,
|
||||
String name) throws IOException {
|
||||
|
||||
ResourceDecompressorFactory fact = factories.get(name);
|
||||
if (fact != null) {
|
||||
return fact.newDecompressor(properties);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void registerReaderProvider(ResourceDecompressorFactory factory) {
|
||||
factories.put(factory.getName(), factory);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javac.internal.jimage.decompressor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* A descriptor parser used to extract java type strings from
|
||||
* UTF_8 descriptors.
|
||||
*
|
||||
* @implNote This class needs to maintain JDK 8 source compatibility.
|
||||
*
|
||||
* It is used internally in the JDK to implement jimage/jrtfs access,
|
||||
* but also compiled and delivered as part of the jrtfs.jar to support access
|
||||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
public class SignatureParser {
|
||||
|
||||
public static class ParseResult {
|
||||
|
||||
public final List<String> types = new ArrayList<>();
|
||||
public String formatted;
|
||||
private ParseResult() {}
|
||||
}
|
||||
|
||||
private SignatureParser() {}
|
||||
|
||||
public static String reconstruct(String formatted, List<String> arguments) {
|
||||
int arg_index = 0;
|
||||
char[] chars = formatted.toCharArray();
|
||||
StringBuilder out = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
char c = chars[i];
|
||||
out.append(c);
|
||||
switch (c) {
|
||||
case 'L': {
|
||||
String pkg = arguments.get(arg_index);
|
||||
if(!pkg.isEmpty()) {
|
||||
out.append(pkg).append("/");
|
||||
}
|
||||
arg_index+=1;
|
||||
out.append(arguments.get(arg_index));
|
||||
arg_index+=1;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
public static ParseResult parseSignatureDescriptor(String str) {
|
||||
ParseResult res = new ParseResult();
|
||||
char[] chars = str.toCharArray();
|
||||
StringBuilder type = null;
|
||||
StringBuilder formatted = new StringBuilder();
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
char c = chars[i];
|
||||
switch (c) {
|
||||
case ';':
|
||||
case ':':
|
||||
case '<': {
|
||||
if(type != null) {
|
||||
String fullName = type.toString();
|
||||
int endIndex = fullName.lastIndexOf("/");
|
||||
String clazz = fullName;
|
||||
String pkg = "";
|
||||
if(endIndex != -1) {
|
||||
pkg = fullName.substring(0, endIndex);
|
||||
clazz = fullName.substring(endIndex+1);
|
||||
}
|
||||
res.types.add(pkg);
|
||||
res.types.add(clazz);
|
||||
}
|
||||
formatted.append(c);
|
||||
|
||||
type = null;
|
||||
break;
|
||||
}
|
||||
case 'L': {
|
||||
if(type == null) {
|
||||
type = new StringBuilder();
|
||||
formatted.append(c);
|
||||
} else {
|
||||
type.append(c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if(type == null) {
|
||||
formatted.append(c);
|
||||
} else {
|
||||
type.append(c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
res.formatted = formatted.toString();
|
||||
return res;
|
||||
}
|
||||
}
|
||||
+240
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javac.internal.jimage.decompressor;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
*
|
||||
* A Decompressor that reconstructs the constant pool of classes.
|
||||
*
|
||||
* @implNote This class needs to maintain JDK 8 source compatibility.
|
||||
*
|
||||
* It is used internally in the JDK to implement jimage/jrtfs access,
|
||||
* but also compiled and delivered as part of the jrtfs.jar to support access
|
||||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
public class StringSharingDecompressor implements ResourceDecompressor {
|
||||
|
||||
public static final int EXTERNALIZED_STRING = 23;
|
||||
public static final int EXTERNALIZED_STRING_DESCRIPTOR = 25;
|
||||
|
||||
private static final int CONSTANT_Utf8 = 1;
|
||||
private static final int CONSTANT_Integer = 3;
|
||||
private static final int CONSTANT_Float = 4;
|
||||
private static final int CONSTANT_Long = 5;
|
||||
private static final int CONSTANT_Double = 6;
|
||||
private static final int CONSTANT_Class = 7;
|
||||
private static final int CONSTANT_String = 8;
|
||||
private static final int CONSTANT_Fieldref = 9;
|
||||
private static final int CONSTANT_Methodref = 10;
|
||||
private static final int CONSTANT_InterfaceMethodref = 11;
|
||||
private static final int CONSTANT_NameAndType = 12;
|
||||
private static final int CONSTANT_MethodHandle = 15;
|
||||
private static final int CONSTANT_MethodType = 16;
|
||||
private static final int CONSTANT_InvokeDynamic = 18;
|
||||
private static final int CONSTANT_Module = 19;
|
||||
private static final int CONSTANT_Package = 20;
|
||||
|
||||
private static final int[] SIZES = new int[21];
|
||||
|
||||
static {
|
||||
|
||||
//SIZES[CONSTANT_Utf8] = XXX;
|
||||
SIZES[CONSTANT_Integer] = 4;
|
||||
SIZES[CONSTANT_Float] = 4;
|
||||
SIZES[CONSTANT_Long] = 8;
|
||||
SIZES[CONSTANT_Double] = 8;
|
||||
SIZES[CONSTANT_Class] = 2;
|
||||
SIZES[CONSTANT_String] = 2;
|
||||
SIZES[CONSTANT_Fieldref] = 4;
|
||||
SIZES[CONSTANT_Methodref] = 4;
|
||||
SIZES[CONSTANT_InterfaceMethodref] = 4;
|
||||
SIZES[CONSTANT_NameAndType] = 4;
|
||||
SIZES[CONSTANT_MethodHandle] = 3;
|
||||
SIZES[CONSTANT_MethodType] = 2;
|
||||
SIZES[CONSTANT_InvokeDynamic] = 4;
|
||||
SIZES[CONSTANT_Module] = 2;
|
||||
SIZES[CONSTANT_Package] = 2;
|
||||
}
|
||||
|
||||
public static int[] getSizes() {
|
||||
return SIZES.clone();
|
||||
}
|
||||
|
||||
@SuppressWarnings("fallthrough")
|
||||
public static byte[] normalize(StringsProvider provider, byte[] transformed,
|
||||
int offset) throws IOException {
|
||||
DataInputStream stream = new DataInputStream(new ByteArrayInputStream(transformed,
|
||||
offset, transformed.length - offset));
|
||||
ByteArrayOutputStream outStream = new ByteArrayOutputStream(transformed.length);
|
||||
DataOutputStream out = new DataOutputStream(outStream);
|
||||
byte[] header = new byte[8]; //maginc/4, minor/2, major/2
|
||||
stream.readFully(header);
|
||||
out.write(header);
|
||||
int count = stream.readUnsignedShort();
|
||||
out.writeShort(count);
|
||||
for (int i = 1; i < count; i++) {
|
||||
int tag = stream.readUnsignedByte();
|
||||
byte[] arr;
|
||||
switch (tag) {
|
||||
case CONSTANT_Utf8: {
|
||||
out.write(tag);
|
||||
String utf = stream.readUTF();
|
||||
out.writeUTF(utf);
|
||||
break;
|
||||
}
|
||||
|
||||
case EXTERNALIZED_STRING: {
|
||||
int index = CompressIndexes.readInt(stream);
|
||||
String orig = provider.getString(index);
|
||||
out.write(CONSTANT_Utf8);
|
||||
out.writeUTF(orig);
|
||||
break;
|
||||
}
|
||||
|
||||
case EXTERNALIZED_STRING_DESCRIPTOR: {
|
||||
String orig = reconstruct(provider, stream);
|
||||
out.write(CONSTANT_Utf8);
|
||||
out.writeUTF(orig);
|
||||
break;
|
||||
}
|
||||
case CONSTANT_Long:
|
||||
case CONSTANT_Double: {
|
||||
i++;
|
||||
}
|
||||
default: {
|
||||
out.write(tag);
|
||||
int size = SIZES[tag];
|
||||
arr = new byte[size];
|
||||
stream.readFully(arr);
|
||||
out.write(arr);
|
||||
}
|
||||
}
|
||||
}
|
||||
out.write(transformed, transformed.length - stream.available(),
|
||||
stream.available());
|
||||
out.flush();
|
||||
|
||||
return outStream.toByteArray();
|
||||
}
|
||||
|
||||
private static String reconstruct(StringsProvider reader, DataInputStream cr)
|
||||
throws IOException {
|
||||
int descIndex = CompressIndexes.readInt(cr);
|
||||
String desc = reader.getString(descIndex);
|
||||
byte[] encodedDesc = getEncoded(desc);
|
||||
int indexes_length = CompressIndexes.readInt(cr);
|
||||
byte[] bytes = new byte[indexes_length];
|
||||
cr.readFully(bytes);
|
||||
List<Integer> indices = CompressIndexes.decompressFlow(bytes);
|
||||
ByteBuffer buffer = ByteBuffer.allocate(encodedDesc.length * 2);
|
||||
buffer.order(ByteOrder.BIG_ENDIAN);
|
||||
int argIndex = 0;
|
||||
for (byte c : encodedDesc) {
|
||||
if (c == 'L') {
|
||||
buffer = safeAdd(buffer, c);
|
||||
int index = indices.get(argIndex);
|
||||
argIndex += 1;
|
||||
String pkg = reader.getString(index);
|
||||
if (!pkg.isEmpty()) {
|
||||
pkg = pkg + "/";
|
||||
byte[] encoded = getEncoded(pkg);
|
||||
buffer = safeAdd(buffer, encoded);
|
||||
}
|
||||
int classIndex = indices.get(argIndex);
|
||||
argIndex += 1;
|
||||
String clazz = reader.getString(classIndex);
|
||||
byte[] encoded = getEncoded(clazz);
|
||||
buffer = safeAdd(buffer, encoded);
|
||||
} else {
|
||||
buffer = safeAdd(buffer, c);
|
||||
}
|
||||
}
|
||||
|
||||
byte[] encoded = buffer.array();
|
||||
ByteBuffer result = ByteBuffer.allocate(encoded.length + 2);
|
||||
result.order(ByteOrder.BIG_ENDIAN);
|
||||
result.putShort((short) buffer.position());
|
||||
result.put(encoded, 0, buffer.position());
|
||||
ByteArrayInputStream stream = new ByteArrayInputStream(result.array());
|
||||
DataInputStream inStream = new DataInputStream(stream);
|
||||
String str = inStream.readUTF();
|
||||
return str;
|
||||
}
|
||||
|
||||
public static byte[] getEncoded(String pre) throws IOException {
|
||||
ByteArrayOutputStream resultStream = new ByteArrayOutputStream();
|
||||
DataOutputStream resultOut = new DataOutputStream(resultStream);
|
||||
resultOut.writeUTF(pre);
|
||||
byte[] content = resultStream.toByteArray();
|
||||
// first 2 items are length;
|
||||
if (content.length <= 2) {
|
||||
return new byte[0];
|
||||
}
|
||||
return Arrays.copyOfRange(content, 2, content.length);
|
||||
}
|
||||
|
||||
private static ByteBuffer safeAdd(ByteBuffer current, byte b) {
|
||||
byte[] bytes = {b};
|
||||
return safeAdd(current, bytes);
|
||||
}
|
||||
|
||||
private static ByteBuffer safeAdd(ByteBuffer current, byte[] bytes) {
|
||||
if (current.remaining() < bytes.length) {
|
||||
ByteBuffer newBuffer = ByteBuffer.allocate((current.capacity()
|
||||
+ bytes.length) * 2);
|
||||
newBuffer.order(ByteOrder.BIG_ENDIAN);
|
||||
newBuffer.put(current.array(), 0, current.position());
|
||||
current = newBuffer;
|
||||
}
|
||||
current.put(bytes);
|
||||
return current;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return StringSharingDecompressorFactory.NAME;
|
||||
}
|
||||
|
||||
public StringSharingDecompressor(Properties properties) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] decompress(StringsProvider reader, byte[] content,
|
||||
int offset, long originalSize) throws Exception {
|
||||
return normalize(reader, content, offset);
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javac.internal.jimage.decompressor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
*
|
||||
* Constant Pool strings sharing Decompressor factory.
|
||||
*
|
||||
* @implNote This class needs to maintain JDK 8 source compatibility.
|
||||
*
|
||||
* It is used internally in the JDK to implement jimage/jrtfs access,
|
||||
* but also compiled and delivered as part of the jrtfs.jar to support access
|
||||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
public class StringSharingDecompressorFactory extends ResourceDecompressorFactory {
|
||||
|
||||
public static final String NAME = "compact-cp";
|
||||
public StringSharingDecompressorFactory() {
|
||||
super(NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceDecompressor newDecompressor(Properties properties)
|
||||
throws IOException {
|
||||
return new StringSharingDecompressor(properties);
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javac.internal.jimage.decompressor;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.zip.Inflater;
|
||||
|
||||
/**
|
||||
*
|
||||
* ZIP Decompressor
|
||||
*
|
||||
* @implNote This class needs to maintain JDK 8 source compatibility.
|
||||
*
|
||||
* It is used internally in the JDK to implement jimage/jrtfs access,
|
||||
* but also compiled and delivered as part of the jrtfs.jar to support access
|
||||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
final class ZipDecompressor implements ResourceDecompressor {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return ZipDecompressorFactory.NAME;
|
||||
}
|
||||
|
||||
static byte[] decompress(byte[] bytesIn, int offset) throws Exception {
|
||||
Inflater inflater = new Inflater();
|
||||
inflater.setInput(bytesIn, offset, bytesIn.length - offset);
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream(bytesIn.length - offset);
|
||||
byte[] buffer = new byte[1024];
|
||||
|
||||
while (!inflater.finished()) {
|
||||
int count = inflater.inflate(buffer);
|
||||
stream.write(buffer, 0, count);
|
||||
}
|
||||
|
||||
stream.close();
|
||||
|
||||
byte[] bytesOut = stream.toByteArray();
|
||||
inflater.end();
|
||||
|
||||
return bytesOut;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] decompress(StringsProvider reader, byte[] content, int offset,
|
||||
long originalSize) throws Exception {
|
||||
byte[] decompressed = decompress(content, offset);
|
||||
return decompressed;
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javac.internal.jimage.decompressor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
*
|
||||
* ZIP decompressor factory
|
||||
*
|
||||
* @implNote This class needs to maintain JDK 8 source compatibility.
|
||||
*
|
||||
* It is used internally in the JDK to implement jimage/jrtfs access,
|
||||
* but also compiled and delivered as part of the jrtfs.jar to support access
|
||||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
public final class ZipDecompressorFactory extends ResourceDecompressorFactory {
|
||||
public static final String NAME = "zip";
|
||||
public ZipDecompressorFactory() {
|
||||
super(NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceDecompressor newDecompressor(Properties properties)
|
||||
throws IOException {
|
||||
return new ZipDecompressor();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javac.internal.jmod;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
/** Helper class to read JMOD file */
|
||||
public class JmodFile implements AutoCloseable {
|
||||
// jmod magic number and version number
|
||||
private static final int JMOD_MAJOR_VERSION = 0x01;
|
||||
private static final int JMOD_MINOR_VERSION = 0x00;
|
||||
private static final byte[] JMOD_MAGIC_NUMBER = {
|
||||
0x4A, 0x4D, /* JM */ JMOD_MAJOR_VERSION, JMOD_MINOR_VERSION, /* version 1.0 */
|
||||
};
|
||||
|
||||
public static void checkMagic(Path file) throws IOException {
|
||||
try (InputStream in = Files.newInputStream(file);
|
||||
BufferedInputStream bis = new BufferedInputStream(in)) {
|
||||
// validate the header
|
||||
byte[] magic = new byte[4];
|
||||
bis.read(magic);
|
||||
if (magic[0] != JMOD_MAGIC_NUMBER[0] || magic[1] != JMOD_MAGIC_NUMBER[1]) {
|
||||
throw new IOException("Invalid JMOD file: " + file.toString());
|
||||
}
|
||||
if (magic[2] > JMOD_MAJOR_VERSION
|
||||
|| (magic[2] == JMOD_MAJOR_VERSION && magic[3] > JMOD_MINOR_VERSION)) {
|
||||
throw new IOException(
|
||||
"Unsupported jmod version: "
|
||||
+ magic[2]
|
||||
+ "."
|
||||
+ magic[3]
|
||||
+ " in "
|
||||
+ file.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** JMOD sections */
|
||||
public static enum Section {
|
||||
CLASSES("classes"),
|
||||
CONFIG("conf"),
|
||||
HEADER_FILES("include"),
|
||||
LEGAL_NOTICES("legal"),
|
||||
MAN_PAGES("man"),
|
||||
NATIVE_LIBS("lib"),
|
||||
NATIVE_CMDS("bin");
|
||||
|
||||
private final String jmodDir;
|
||||
|
||||
private Section(String jmodDir) {
|
||||
this.jmodDir = jmodDir;
|
||||
}
|
||||
|
||||
/** Returns the directory name in the JMOD file corresponding to this section */
|
||||
public String jmodDir() {
|
||||
return jmodDir;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JMOD file entry.
|
||||
*
|
||||
* <p>Each entry corresponds to a ZipEntry whose name is: Section::jmodDir + '/' + name
|
||||
*/
|
||||
public static class Entry {
|
||||
private final ZipEntry zipEntry;
|
||||
private final Section section;
|
||||
private final String name;
|
||||
|
||||
private Entry(ZipEntry e) {
|
||||
String name = e.getName();
|
||||
int i = name.indexOf('/');
|
||||
if (i <= 1) {
|
||||
throw new RuntimeException("invalid jmod entry: " + name);
|
||||
}
|
||||
|
||||
this.zipEntry = e;
|
||||
this.section = section(name.substring(0, i));
|
||||
this.name = name.substring(i + 1);
|
||||
}
|
||||
|
||||
/** Returns the section of this entry. */
|
||||
public Section section() {
|
||||
return section;
|
||||
}
|
||||
|
||||
/** Returns the name of this entry. */
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/** Returns true if the entry is a directory in the JMOD file. */
|
||||
public boolean isDirectory() {
|
||||
return zipEntry.isDirectory();
|
||||
}
|
||||
|
||||
/** Returns the size of this entry. */
|
||||
public long size() {
|
||||
return zipEntry.getSize();
|
||||
}
|
||||
|
||||
public ZipEntry zipEntry() {
|
||||
return zipEntry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return section.jmodDir() + "/" + name;
|
||||
}
|
||||
|
||||
/*
|
||||
* A map from the jmodDir name to Section
|
||||
*/
|
||||
static final Map<String, Section> NAME_TO_SECTION =
|
||||
Arrays.stream(Section.values())
|
||||
.collect(Collectors.toMap(Section::jmodDir, Function.identity()));
|
||||
|
||||
static Section section(String name) {
|
||||
if (!NAME_TO_SECTION.containsKey(name)) {
|
||||
throw new IllegalArgumentException("invalid section: " + name);
|
||||
}
|
||||
return NAME_TO_SECTION.get(name);
|
||||
}
|
||||
}
|
||||
|
||||
private final Path file;
|
||||
private final ZipFile zipfile;
|
||||
|
||||
/** Constructs a {@code JmodFile} from a given path. */
|
||||
public JmodFile(Path file) throws IOException {
|
||||
checkMagic(file);
|
||||
this.file = file;
|
||||
this.zipfile = new ZipFile(file.toFile());
|
||||
}
|
||||
|
||||
public static void writeMagicNumber(OutputStream os) throws IOException {
|
||||
os.write(JMOD_MAGIC_NUMBER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code Entry} for a resource in a JMOD file section or {@code null} if not found.
|
||||
*/
|
||||
public Entry getEntry(Section section, String name) {
|
||||
String entry = section.jmodDir() + "/" + name;
|
||||
ZipEntry ze = zipfile.getEntry(entry);
|
||||
return (ze != null) ? new Entry(ze) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens an {@code InputStream} for reading the named entry of the given section in this JMOD
|
||||
* file.
|
||||
*
|
||||
* @throws IOException if the named entry is not found, or I/O error occurs when reading it
|
||||
*/
|
||||
public InputStream getInputStream(Section section, String name) throws IOException {
|
||||
String entry = section.jmodDir() + "/" + name;
|
||||
ZipEntry e = zipfile.getEntry(entry);
|
||||
if (e == null) {
|
||||
throw new IOException(name + " not found: " + file);
|
||||
}
|
||||
return zipfile.getInputStream(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens an {@code InputStream} for reading an entry in the JMOD file.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
public InputStream getInputStream(Entry entry) throws IOException {
|
||||
return zipfile.getInputStream(entry.zipEntry());
|
||||
}
|
||||
|
||||
/** Returns a stream of entries in this JMOD file. */
|
||||
public Stream<Entry> stream() {
|
||||
return zipfile.stream().map(Entry::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (zipfile != null) {
|
||||
zipfile.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,305 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javac.internal.jrtfs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystemException;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javac.internal.jimage.ImageReader.Node;
|
||||
|
||||
/**
|
||||
* A jrt file system built on $JAVA_HOME/modules directory ('exploded modules
|
||||
* build')
|
||||
*
|
||||
* @implNote This class needs to maintain JDK 8 source compatibility.
|
||||
*
|
||||
* It is used internally in the JDK to implement jimage/jrtfs access,
|
||||
* but also compiled and delivered as part of the jrtfs.jar to support access
|
||||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
class ExplodedImage extends SystemImage {
|
||||
|
||||
private static final String MODULES = "/modules/";
|
||||
private static final String PACKAGES = "/packages/";
|
||||
private static final int PACKAGES_LEN = PACKAGES.length();
|
||||
|
||||
private final FileSystem defaultFS;
|
||||
private final String separator;
|
||||
private final Map<String, PathNode> nodes = Collections.synchronizedMap(new HashMap<>());
|
||||
private final BasicFileAttributes modulesDirAttrs;
|
||||
|
||||
ExplodedImage(Path modulesDir) throws IOException {
|
||||
defaultFS = FileSystems.getDefault();
|
||||
String str = defaultFS.getSeparator();
|
||||
separator = str.equals("/") ? null : str;
|
||||
modulesDirAttrs = Files.readAttributes(modulesDir, BasicFileAttributes.class);
|
||||
initNodes();
|
||||
}
|
||||
|
||||
// A Node that is backed by actual default file system Path
|
||||
private final class PathNode extends Node {
|
||||
|
||||
// Path in underlying default file system
|
||||
private Path path;
|
||||
private PathNode link;
|
||||
private List<Node> children;
|
||||
|
||||
PathNode(String name, Path path, BasicFileAttributes attrs) { // path
|
||||
super(name, attrs);
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
PathNode(String name, Node link) { // link
|
||||
super(name, link.getFileAttributes());
|
||||
this.link = (PathNode)link;
|
||||
}
|
||||
|
||||
PathNode(String name, List<Node> children) { // dir
|
||||
super(name, modulesDirAttrs);
|
||||
this.children = children;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirectory() {
|
||||
return children != null ||
|
||||
(link == null && getFileAttributes().isDirectory());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLink() {
|
||||
return link != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PathNode resolveLink(boolean recursive) {
|
||||
if (link == null)
|
||||
return this;
|
||||
return recursive && link.isLink() ? link.resolveLink(true) : link;
|
||||
}
|
||||
|
||||
byte[] getContent() throws IOException {
|
||||
if (!getFileAttributes().isRegularFile())
|
||||
throw new FileSystemException(getName() + " is not file");
|
||||
return Files.readAllBytes(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Node> getChildren() {
|
||||
if (!isDirectory())
|
||||
throw new IllegalArgumentException("not a directory: " + getNameString());
|
||||
if (children == null) {
|
||||
List<Node> list = new ArrayList<>();
|
||||
try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) {
|
||||
for (Path p : stream) {
|
||||
p = explodedModulesDir.relativize(p);
|
||||
String pName = MODULES + nativeSlashToFrontSlash(p.toString());
|
||||
Node node = findNode(pName);
|
||||
if (node != null) { // findNode may choose to hide certain files!
|
||||
list.add(node);
|
||||
}
|
||||
}
|
||||
} catch (IOException x) {
|
||||
return null;
|
||||
}
|
||||
children = list;
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long size() {
|
||||
try {
|
||||
return isDirectory() ? 0 : Files.size(path);
|
||||
} catch (IOException ex) {
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
nodes.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getResource(Node node) throws IOException {
|
||||
return ((PathNode)node).getContent();
|
||||
}
|
||||
|
||||
// find Node for the given Path
|
||||
@Override
|
||||
public synchronized Node findNode(String str) {
|
||||
Node node = findModulesNode(str);
|
||||
if (node != null) {
|
||||
return node;
|
||||
}
|
||||
// lazily created for paths like /packages/<package>/<module>/xyz
|
||||
// For example /packages/java.lang/java.base/java/lang/
|
||||
if (str.startsWith(PACKAGES)) {
|
||||
// pkgEndIdx marks end of <package> part
|
||||
int pkgEndIdx = str.indexOf('/', PACKAGES_LEN);
|
||||
if (pkgEndIdx != -1) {
|
||||
// modEndIdx marks end of <module> part
|
||||
int modEndIdx = str.indexOf('/', pkgEndIdx + 1);
|
||||
if (modEndIdx != -1) {
|
||||
// make sure we have such module link!
|
||||
// ie., /packages/<package>/<module> is valid
|
||||
Node linkNode = nodes.get(str.substring(0, modEndIdx));
|
||||
if (linkNode == null || !linkNode.isLink()) {
|
||||
return null;
|
||||
}
|
||||
// map to "/modules/zyz" path and return that node
|
||||
// For example, "/modules/java.base/java/lang" for
|
||||
// "/packages/java.lang/java.base/java/lang".
|
||||
String mod = MODULES + str.substring(pkgEndIdx + 1);
|
||||
return findModulesNode(mod);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// find a Node for a path that starts like "/modules/..."
|
||||
Node findModulesNode(String str) {
|
||||
PathNode node = nodes.get(str);
|
||||
if (node != null) {
|
||||
return node;
|
||||
}
|
||||
// lazily created "/modules/xyz/abc/" Node
|
||||
// This is mapped to default file system path "<JDK_MODULES_DIR>/xyz/abc"
|
||||
Path p = underlyingPath(str);
|
||||
if (p != null) {
|
||||
try {
|
||||
BasicFileAttributes attrs = Files.readAttributes(p, BasicFileAttributes.class);
|
||||
if (attrs.isRegularFile()) {
|
||||
Path f = p.getFileName();
|
||||
if (f.toString().startsWith("_the."))
|
||||
return null;
|
||||
}
|
||||
node = new PathNode(str, p, attrs);
|
||||
nodes.put(str, node);
|
||||
return node;
|
||||
} catch (IOException x) {
|
||||
// does not exists or unable to determine
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Path underlyingPath(String str) {
|
||||
if (str.startsWith(MODULES)) {
|
||||
str = frontSlashToNativeSlash(str.substring("/modules".length()));
|
||||
return defaultFS.getPath(explodedModulesDir.toString(), str);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// convert "/" to platform path separator
|
||||
private String frontSlashToNativeSlash(String str) {
|
||||
return separator == null ? str : str.replace("/", separator);
|
||||
}
|
||||
|
||||
// convert platform path separator to "/"
|
||||
private String nativeSlashToFrontSlash(String str) {
|
||||
return separator == null ? str : str.replace(separator, "/");
|
||||
}
|
||||
|
||||
// convert "/"s to "."s
|
||||
private String slashesToDots(String str) {
|
||||
return str.replace(separator != null ? separator : "/", ".");
|
||||
}
|
||||
|
||||
// initialize file system Nodes
|
||||
private void initNodes() throws IOException {
|
||||
// same package prefix may exist in mutliple modules. This Map
|
||||
// is filled by walking "jdk modules" directory recursively!
|
||||
Map<String, List<String>> packageToModules = new HashMap<>();
|
||||
try (DirectoryStream<Path> stream = Files.newDirectoryStream(explodedModulesDir)) {
|
||||
for (Path module : stream) {
|
||||
if (Files.isDirectory(module)) {
|
||||
String moduleName = module.getFileName().toString();
|
||||
// make sure "/modules/<moduleName>" is created
|
||||
findModulesNode(MODULES + moduleName);
|
||||
Files.walk(module).filter(Files::isDirectory).forEach((p) -> {
|
||||
p = module.relativize(p);
|
||||
String pkgName = slashesToDots(p.toString());
|
||||
// skip META-INFO and empty strings
|
||||
if (!pkgName.isEmpty() && !pkgName.startsWith("META-INF")) {
|
||||
List<String> moduleNames = packageToModules.get(pkgName);
|
||||
if (moduleNames == null) {
|
||||
moduleNames = new ArrayList<>();
|
||||
packageToModules.put(pkgName, moduleNames);
|
||||
}
|
||||
moduleNames.add(moduleName);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
// create "/modules" directory
|
||||
// "nodes" map contains only /modules/<foo> nodes only so far and so add all as children of /modules
|
||||
PathNode modulesDir = new PathNode("/modules", new ArrayList<>(nodes.values()));
|
||||
nodes.put(modulesDir.getName(), modulesDir);
|
||||
|
||||
// create children under "/packages"
|
||||
List<Node> packagesChildren = new ArrayList<>(packageToModules.size());
|
||||
for (Map.Entry<String, List<String>> entry : packageToModules.entrySet()) {
|
||||
String pkgName = entry.getKey();
|
||||
List<String> moduleNameList = entry.getValue();
|
||||
List<Node> moduleLinkNodes = new ArrayList<>(moduleNameList.size());
|
||||
for (String moduleName : moduleNameList) {
|
||||
Node moduleNode = findModulesNode(MODULES + moduleName);
|
||||
PathNode linkNode = new PathNode(PACKAGES + pkgName + "/" + moduleName, moduleNode);
|
||||
nodes.put(linkNode.getName(), linkNode);
|
||||
moduleLinkNodes.add(linkNode);
|
||||
}
|
||||
PathNode pkgDir = new PathNode(PACKAGES + pkgName, moduleLinkNodes);
|
||||
nodes.put(pkgDir.getName(), pkgDir);
|
||||
packagesChildren.add(pkgDir);
|
||||
}
|
||||
// "/packages" dir
|
||||
PathNode packagesDir = new PathNode("/packages", packagesChildren);
|
||||
nodes.put(packagesDir.getName(), packagesDir);
|
||||
|
||||
// finally "/" dir!
|
||||
List<Node> rootChildren = new ArrayList<>();
|
||||
rootChildren.add(packagesDir);
|
||||
rootChildren.add(modulesDir);
|
||||
PathNode root = new PathNode("/", rootChildren);
|
||||
nodes.put(root.getName(), root);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javac.internal.jrtfs;
|
||||
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.ClosedDirectoryStreamException;
|
||||
import java.nio.file.NotDirectoryException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* DirectoryStream implementation for jrt file system implementations.
|
||||
*
|
||||
* @implNote This class needs to maintain JDK 8 source compatibility.
|
||||
*
|
||||
* It is used internally in the JDK to implement jimage/jrtfs access,
|
||||
* but also compiled and delivered as part of the jrtfs.jar to support access
|
||||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
final class JrtDirectoryStream implements DirectoryStream<Path> {
|
||||
|
||||
private final JrtPath dir;
|
||||
private final DirectoryStream.Filter<? super Path> filter;
|
||||
private boolean isClosed;
|
||||
private Iterator<Path> itr;
|
||||
|
||||
JrtDirectoryStream(JrtPath dir,
|
||||
DirectoryStream.Filter<? super java.nio.file.Path> filter)
|
||||
throws IOException
|
||||
{
|
||||
this.dir = dir;
|
||||
if (!dir.jrtfs.isDirectory(dir, true)) { // sanity check
|
||||
throw new NotDirectoryException(dir.toString());
|
||||
}
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Iterator<Path> iterator() {
|
||||
if (isClosed)
|
||||
throw new ClosedDirectoryStreamException();
|
||||
if (itr != null)
|
||||
throw new IllegalStateException("Iterator has already been returned");
|
||||
try {
|
||||
itr = dir.jrtfs.iteratorOf(dir, filter);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
return new Iterator<Path>() {
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
synchronized (JrtDirectoryStream.this) {
|
||||
if (isClosed)
|
||||
return false;
|
||||
return itr.hasNext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path next() {
|
||||
synchronized (JrtDirectoryStream.this) {
|
||||
if (isClosed)
|
||||
throw new NoSuchElementException();
|
||||
return itr.next();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void close() throws IOException {
|
||||
isClosed = true;
|
||||
}
|
||||
}
|
||||
+198
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javac.internal.jrtfs;
|
||||
|
||||
import java.nio.file.LinkOption;
|
||||
import java.nio.file.attribute.*;
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* File attribute view for jrt file system.
|
||||
*
|
||||
* @implNote This class needs to maintain JDK 8 source compatibility.
|
||||
*
|
||||
* It is used internally in the JDK to implement jimage/jrtfs access,
|
||||
* but also compiled and delivered as part of the jrtfs.jar to support access
|
||||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
final class JrtFileAttributeView implements BasicFileAttributeView {
|
||||
|
||||
private static enum AttrID {
|
||||
size,
|
||||
creationTime,
|
||||
lastAccessTime,
|
||||
lastModifiedTime,
|
||||
isDirectory,
|
||||
isRegularFile,
|
||||
isSymbolicLink,
|
||||
isOther,
|
||||
fileKey,
|
||||
compressedSize,
|
||||
extension
|
||||
};
|
||||
|
||||
private final JrtPath path;
|
||||
private final boolean isJrtView;
|
||||
private final LinkOption[] options;
|
||||
|
||||
private JrtFileAttributeView(JrtPath path, boolean isJrtView, LinkOption... options) {
|
||||
this.path = path;
|
||||
this.isJrtView = isJrtView;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // Cast to V
|
||||
static <V extends FileAttributeView> V get(JrtPath path, Class<V> type, LinkOption... options) {
|
||||
Objects.requireNonNull(type);
|
||||
if (type == BasicFileAttributeView.class) {
|
||||
return (V) new JrtFileAttributeView(path, false, options);
|
||||
}
|
||||
if (type == JrtFileAttributeView.class) {
|
||||
return (V) new JrtFileAttributeView(path, true, options);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static JrtFileAttributeView get(JrtPath path, String type, LinkOption... options) {
|
||||
Objects.requireNonNull(type);
|
||||
if (type.equals("basic")) {
|
||||
return new JrtFileAttributeView(path, false, options);
|
||||
}
|
||||
if (type.equals("jrt")) {
|
||||
return new JrtFileAttributeView(path, true, options);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return isJrtView ? "jrt" : "basic";
|
||||
}
|
||||
|
||||
@Override
|
||||
public JrtFileAttributes readAttributes() throws IOException {
|
||||
return path.getAttributes(options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimes(FileTime lastModifiedTime,
|
||||
FileTime lastAccessTime,
|
||||
FileTime createTime) throws IOException {
|
||||
path.setTimes(lastModifiedTime, lastAccessTime, createTime);
|
||||
}
|
||||
|
||||
static void setAttribute(JrtPath path, String attribute, Object value)
|
||||
throws IOException {
|
||||
int colonPos = attribute.indexOf(':');
|
||||
if (colonPos != -1) { // type = "basic", if no ":"
|
||||
String type = attribute.substring(0, colonPos++);
|
||||
if (!type.equals("basic") && !type.equals("jrt")) {
|
||||
throw new UnsupportedOperationException(
|
||||
"view <" + type + "> is not supported");
|
||||
}
|
||||
attribute = attribute.substring(colonPos);
|
||||
}
|
||||
try {
|
||||
AttrID id = AttrID.valueOf(attribute);
|
||||
if (id == AttrID.lastModifiedTime) {
|
||||
path.setTimes((FileTime) value, null, null);
|
||||
} else if (id == AttrID.lastAccessTime) {
|
||||
path.setTimes(null, (FileTime) value, null);
|
||||
} else if (id == AttrID.creationTime) {
|
||||
path.setTimes(null, null, (FileTime) value);
|
||||
}
|
||||
return;
|
||||
} catch (IllegalArgumentException x) {}
|
||||
throw new UnsupportedOperationException("'" + attribute
|
||||
+ "' is unknown or read-only attribute");
|
||||
}
|
||||
|
||||
static Map<String, Object> readAttributes(JrtPath path, String attributes,
|
||||
LinkOption... options)
|
||||
throws IOException {
|
||||
int colonPos = attributes.indexOf(':');
|
||||
boolean isJrtView = false;
|
||||
if (colonPos != -1) { // type = "basic", if no ":"
|
||||
String type = attributes.substring(0, colonPos++);
|
||||
if (!type.equals("basic") && !type.equals("jrt")) {
|
||||
throw new UnsupportedOperationException("view <" + type +
|
||||
"> is not supported");
|
||||
}
|
||||
isJrtView = true;
|
||||
attributes = attributes.substring(colonPos);
|
||||
}
|
||||
JrtFileAttributes jrtfas = path.getAttributes();
|
||||
LinkedHashMap<String, Object> map = new LinkedHashMap<>();
|
||||
if ("*".equals(attributes)) {
|
||||
for (AttrID id : AttrID.values()) {
|
||||
map.put(id.name(), attribute(id, jrtfas, isJrtView));
|
||||
}
|
||||
} else {
|
||||
String[] as = attributes.split(",");
|
||||
for (String a : as) {
|
||||
//throw IllegalArgumentException
|
||||
map.put(a, attribute(AttrID.valueOf(a), jrtfas, isJrtView));
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
static Object attribute(AttrID id, JrtFileAttributes jrtfas, boolean isJrtView) {
|
||||
switch (id) {
|
||||
case size:
|
||||
return jrtfas.size();
|
||||
case creationTime:
|
||||
return jrtfas.creationTime();
|
||||
case lastAccessTime:
|
||||
return jrtfas.lastAccessTime();
|
||||
case lastModifiedTime:
|
||||
return jrtfas.lastModifiedTime();
|
||||
case isDirectory:
|
||||
return jrtfas.isDirectory();
|
||||
case isRegularFile:
|
||||
return jrtfas.isRegularFile();
|
||||
case isSymbolicLink:
|
||||
return jrtfas.isSymbolicLink();
|
||||
case isOther:
|
||||
return jrtfas.isOther();
|
||||
case fileKey:
|
||||
return jrtfas.fileKey();
|
||||
case compressedSize:
|
||||
if (isJrtView) {
|
||||
return jrtfas.compressedSize();
|
||||
}
|
||||
break;
|
||||
case extension:
|
||||
if (isJrtView) {
|
||||
return jrtfas.extension();
|
||||
}
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javac.internal.jrtfs;
|
||||
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.util.Formatter;
|
||||
|
||||
import javac.internal.jimage.ImageReader.Node;
|
||||
|
||||
/**
|
||||
* File attributes implementation for jrt image file system.
|
||||
*
|
||||
* @implNote This class needs to maintain JDK 8 source compatibility.
|
||||
*
|
||||
* It is used internally in the JDK to implement jimage/jrtfs access,
|
||||
* but also compiled and delivered as part of the jrtfs.jar to support access
|
||||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
final class JrtFileAttributes implements BasicFileAttributes {
|
||||
|
||||
private final Node node;
|
||||
|
||||
JrtFileAttributes(Node node) {
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
///////// basic attributes ///////////
|
||||
@Override
|
||||
public FileTime creationTime() {
|
||||
return node.creationTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirectory() {
|
||||
return node.isDirectory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOther() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRegularFile() {
|
||||
return !isDirectory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTime lastAccessTime() {
|
||||
return node.lastAccessTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTime lastModifiedTime() {
|
||||
return node.lastModifiedTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long size() {
|
||||
return node.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSymbolicLink() {
|
||||
return node.isLink();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fileKey() {
|
||||
return node.resolveLink(true);
|
||||
}
|
||||
|
||||
///////// jrtfs specific attributes ///////////
|
||||
/**
|
||||
* Compressed resource file. If not available or not applicable, 0L is
|
||||
* returned.
|
||||
*
|
||||
* @return the compressed resource size for compressed resources.
|
||||
*/
|
||||
public long compressedSize() {
|
||||
return node.compressedSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* "file" extension of a file resource.
|
||||
*
|
||||
* @return extension string for the file resource
|
||||
*/
|
||||
public String extension() {
|
||||
return node.extension();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String toString() {
|
||||
StringBuilder sb = new StringBuilder(1024);
|
||||
try (Formatter fm = new Formatter(sb)) {
|
||||
if (creationTime() != null) {
|
||||
fm.format(" creationTime : %tc%n", creationTime().toMillis());
|
||||
} else {
|
||||
fm.format(" creationTime : null%n");
|
||||
}
|
||||
if (lastAccessTime() != null) {
|
||||
fm.format(" lastAccessTime : %tc%n", lastAccessTime().toMillis());
|
||||
} else {
|
||||
fm.format(" lastAccessTime : null%n");
|
||||
}
|
||||
fm.format(" lastModifiedTime: %tc%n", lastModifiedTime().toMillis());
|
||||
fm.format(" isRegularFile : %b%n", isRegularFile());
|
||||
fm.format(" isDirectory : %b%n", isDirectory());
|
||||
fm.format(" isSymbolicLink : %b%n", isSymbolicLink());
|
||||
fm.format(" isOther : %b%n", isOther());
|
||||
fm.format(" fileKey : %s%n", fileKey());
|
||||
fm.format(" size : %d%n", size());
|
||||
fm.format(" compressedSize : %d%n", compressedSize());
|
||||
fm.format(" extension : %s%n", extension());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javac.internal.jrtfs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileStore;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.attribute.FileAttributeView;
|
||||
import java.nio.file.attribute.BasicFileAttributeView;
|
||||
import java.nio.file.attribute.FileStoreAttributeView;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* File store implementation for jrt file systems.
|
||||
*
|
||||
* @implNote This class needs to maintain JDK 8 source compatibility.
|
||||
*
|
||||
* It is used internally in the JDK to implement jimage/jrtfs access,
|
||||
* but also compiled and delivered as part of the jrtfs.jar to support access
|
||||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
final class JrtFileStore extends FileStore {
|
||||
|
||||
protected final FileSystem jrtfs;
|
||||
|
||||
JrtFileStore(JrtPath jrtPath) {
|
||||
this.jrtfs = jrtPath.getFileSystem();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return jrtfs.toString() + "/";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return "jrtfs";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return jrtfs.isReadOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsFileAttributeView(String name) {
|
||||
return name.equals("basic") || name.equals("jrt");
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <V extends FileStoreAttributeView> V getFileStoreAttributeView(Class<V> type) {
|
||||
Objects.requireNonNull(type, "type");
|
||||
return (V) null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTotalSpace() throws IOException {
|
||||
throw new UnsupportedOperationException("getTotalSpace");
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getUsableSpace() throws IOException {
|
||||
throw new UnsupportedOperationException("getUsableSpace");
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getUnallocatedSpace() throws IOException {
|
||||
throw new UnsupportedOperationException("getUnallocatedSpace");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(String attribute) throws IOException {
|
||||
throw new UnsupportedOperationException("does not support " + attribute);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) {
|
||||
return type == BasicFileAttributeView.class ||
|
||||
type == JrtFileAttributeView.class;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,490 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javac.internal.jrtfs;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.NonWritableChannelException;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.SeekableByteChannel;
|
||||
import java.nio.file.ClosedFileSystemException;
|
||||
import java.nio.file.CopyOption;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.FileStore;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystemException;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.LinkOption;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.NotDirectoryException;
|
||||
import java.nio.file.OpenOption;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.PathMatcher;
|
||||
import java.nio.file.ReadOnlyFileSystemException;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.nio.file.WatchService;
|
||||
import java.nio.file.attribute.FileAttribute;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.nio.file.attribute.UserPrincipalLookupService;
|
||||
import java.nio.file.spi.FileSystemProvider;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javac.internal.jimage.ImageReader.Node;
|
||||
|
||||
/**
|
||||
* jrt file system implementation built on System jimage files.
|
||||
*
|
||||
* @implNote This class needs to maintain JDK 8 source compatibility.
|
||||
*
|
||||
* It is used internally in the JDK to implement jimage/jrtfs access,
|
||||
* but also compiled and delivered as part of the jrtfs.jar to support access
|
||||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
class JrtFileSystem extends FileSystem {
|
||||
|
||||
private final JrtFileSystemProvider provider;
|
||||
private final JrtPath rootPath = new JrtPath(this, "/");
|
||||
private volatile boolean isOpen;
|
||||
private volatile boolean isClosable;
|
||||
private SystemImage image;
|
||||
|
||||
JrtFileSystem(JrtFileSystemProvider provider, Map<String, ?> env)
|
||||
throws IOException
|
||||
{
|
||||
this.provider = provider;
|
||||
this.image = SystemImage.open(); // open image file
|
||||
this.isOpen = true;
|
||||
this.isClosable = env != null;
|
||||
}
|
||||
|
||||
// FileSystem method implementations
|
||||
@Override
|
||||
public boolean isOpen() {
|
||||
return isOpen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (!isClosable)
|
||||
throw new UnsupportedOperationException();
|
||||
cleanup();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileSystemProvider provider() {
|
||||
return provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Path> getRootDirectories() {
|
||||
return Collections.singleton(getRootPath());
|
||||
}
|
||||
|
||||
@Override
|
||||
public JrtPath getPath(String first, String... more) {
|
||||
if (more.length == 0) {
|
||||
return new JrtPath(this, first);
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(first);
|
||||
for (String path : more) {
|
||||
if (!path.isEmpty()) {
|
||||
if (sb.length() > 0) {
|
||||
sb.append('/');
|
||||
}
|
||||
sb.append(path);
|
||||
}
|
||||
}
|
||||
return new JrtPath(this, sb.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isReadOnly() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final UserPrincipalLookupService getUserPrincipalLookupService() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WatchService newWatchService() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Iterable<FileStore> getFileStores() {
|
||||
return Collections.singleton(getFileStore(getRootPath()));
|
||||
}
|
||||
|
||||
private static final Set<String> supportedFileAttributeViews
|
||||
= Collections.unmodifiableSet(
|
||||
new HashSet<String>(Arrays.asList("basic", "jrt")));
|
||||
|
||||
@Override
|
||||
public final Set<String> supportedFileAttributeViews() {
|
||||
return supportedFileAttributeViews;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String toString() {
|
||||
return "jrt:/";
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSeparator() {
|
||||
return "/";
|
||||
}
|
||||
|
||||
@Override
|
||||
public PathMatcher getPathMatcher(String syntaxAndInput) {
|
||||
int pos = syntaxAndInput.indexOf(':');
|
||||
if (pos <= 0 || pos == syntaxAndInput.length()) {
|
||||
throw new IllegalArgumentException("pos is " + pos);
|
||||
}
|
||||
String syntax = syntaxAndInput.substring(0, pos);
|
||||
String input = syntaxAndInput.substring(pos + 1);
|
||||
String expr;
|
||||
if (syntax.equalsIgnoreCase("glob")) {
|
||||
expr = JrtUtils.toRegexPattern(input);
|
||||
} else if (syntax.equalsIgnoreCase("regex")) {
|
||||
expr = input;
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Syntax '" + syntax
|
||||
+ "' not recognized");
|
||||
}
|
||||
// return matcher
|
||||
final Pattern pattern = Pattern.compile(expr);
|
||||
return (Path path) -> pattern.matcher(path.toString()).matches();
|
||||
}
|
||||
|
||||
JrtPath resolveLink(JrtPath path) throws IOException {
|
||||
Node node = checkNode(path);
|
||||
if (node.isLink()) {
|
||||
node = node.resolveLink();
|
||||
return new JrtPath(this, node.getName()); // TBD, normalized?
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
JrtFileAttributes getFileAttributes(JrtPath path, LinkOption... options)
|
||||
throws IOException {
|
||||
Node node = checkNode(path);
|
||||
if (node.isLink() && followLinks(options)) {
|
||||
return new JrtFileAttributes(node.resolveLink(true));
|
||||
}
|
||||
return new JrtFileAttributes(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the list of child paths of the given directory "path"
|
||||
*
|
||||
* @param path name of the directory whose content is listed
|
||||
* @return iterator for child paths of the given directory path
|
||||
*/
|
||||
Iterator<Path> iteratorOf(JrtPath path, DirectoryStream.Filter<? super Path> filter)
|
||||
throws IOException {
|
||||
Node node = checkNode(path).resolveLink(true);
|
||||
if (!node.isDirectory()) {
|
||||
throw new NotDirectoryException(path.getName());
|
||||
}
|
||||
if (filter == null) {
|
||||
return node.getChildren()
|
||||
.stream()
|
||||
.map(child -> (Path)(path.resolve(new JrtPath(this, child.getNameString()).getFileName())))
|
||||
.iterator();
|
||||
}
|
||||
return node.getChildren()
|
||||
.stream()
|
||||
.map(child -> (Path)(path.resolve(new JrtPath(this, child.getNameString()).getFileName())))
|
||||
.filter(p -> { try { return filter.accept(p);
|
||||
} catch (IOException x) {}
|
||||
return false;
|
||||
})
|
||||
.iterator();
|
||||
}
|
||||
|
||||
// returns the content of the file resource specified by the path
|
||||
byte[] getFileContent(JrtPath path) throws IOException {
|
||||
Node node = checkNode(path);
|
||||
if (node.isDirectory()) {
|
||||
throw new FileSystemException(path + " is a directory");
|
||||
}
|
||||
//assert node.isResource() : "resource node expected here";
|
||||
return image.getResource(node);
|
||||
}
|
||||
|
||||
/////////////// Implementation details below this point //////////
|
||||
|
||||
// static utility methods
|
||||
static ReadOnlyFileSystemException readOnly() {
|
||||
return new ReadOnlyFileSystemException();
|
||||
}
|
||||
|
||||
// do the supplied options imply that we have to chase symlinks?
|
||||
static boolean followLinks(LinkOption... options) {
|
||||
if (options != null) {
|
||||
for (LinkOption lo : options) {
|
||||
Objects.requireNonNull(lo);
|
||||
if (lo == LinkOption.NOFOLLOW_LINKS) {
|
||||
return false;
|
||||
} else {
|
||||
throw new AssertionError("should not reach here");
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// check that the options passed are supported by (read-only) jrt file system
|
||||
static void checkOptions(Set<? extends OpenOption> options) {
|
||||
// check for options of null type and option is an intance of StandardOpenOption
|
||||
for (OpenOption option : options) {
|
||||
Objects.requireNonNull(option);
|
||||
if (!(option instanceof StandardOpenOption)) {
|
||||
throw new IllegalArgumentException(
|
||||
"option class: " + option.getClass());
|
||||
}
|
||||
}
|
||||
if (options.contains(StandardOpenOption.WRITE) ||
|
||||
options.contains(StandardOpenOption.APPEND)) {
|
||||
throw readOnly();
|
||||
}
|
||||
}
|
||||
|
||||
// clean up this file system - called from finalize and close
|
||||
synchronized void cleanup() throws IOException {
|
||||
if (isOpen) {
|
||||
isOpen = false;
|
||||
image.close();
|
||||
image = null;
|
||||
}
|
||||
}
|
||||
|
||||
// These methods throw read only file system exception
|
||||
final void setTimes(JrtPath jrtPath, FileTime mtime, FileTime atime, FileTime ctime)
|
||||
throws IOException {
|
||||
throw readOnly();
|
||||
}
|
||||
|
||||
// These methods throw read only file system exception
|
||||
final void createDirectory(JrtPath jrtPath, FileAttribute<?>... attrs) throws IOException {
|
||||
throw readOnly();
|
||||
}
|
||||
|
||||
final void deleteFile(JrtPath jrtPath, boolean failIfNotExists)
|
||||
throws IOException {
|
||||
throw readOnly();
|
||||
}
|
||||
|
||||
final OutputStream newOutputStream(JrtPath jrtPath, OpenOption... options)
|
||||
throws IOException {
|
||||
throw readOnly();
|
||||
}
|
||||
|
||||
final void copyFile(boolean deletesrc, JrtPath srcPath, JrtPath dstPath, CopyOption... options)
|
||||
throws IOException {
|
||||
throw readOnly();
|
||||
}
|
||||
|
||||
final FileChannel newFileChannel(JrtPath path,
|
||||
Set<? extends OpenOption> options,
|
||||
FileAttribute<?>... attrs)
|
||||
throws IOException {
|
||||
throw new UnsupportedOperationException("newFileChannel");
|
||||
}
|
||||
|
||||
final InputStream newInputStream(JrtPath path) throws IOException {
|
||||
return new ByteArrayInputStream(getFileContent(path));
|
||||
}
|
||||
|
||||
final SeekableByteChannel newByteChannel(JrtPath path,
|
||||
Set<? extends OpenOption> options,
|
||||
FileAttribute<?>... attrs)
|
||||
throws IOException {
|
||||
checkOptions(options);
|
||||
|
||||
byte[] buf = getFileContent(path);
|
||||
final ReadableByteChannel rbc
|
||||
= Channels.newChannel(new ByteArrayInputStream(buf));
|
||||
final long size = buf.length;
|
||||
return new SeekableByteChannel() {
|
||||
long read = 0;
|
||||
|
||||
@Override
|
||||
public boolean isOpen() {
|
||||
return rbc.isOpen();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long position() throws IOException {
|
||||
return read;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SeekableByteChannel position(long pos)
|
||||
throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(ByteBuffer dst) throws IOException {
|
||||
int n = rbc.read(dst);
|
||||
if (n > 0) {
|
||||
read += n;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SeekableByteChannel truncate(long size)
|
||||
throws IOException {
|
||||
throw new NonWritableChannelException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int write(ByteBuffer src) throws IOException {
|
||||
throw new NonWritableChannelException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long size() throws IOException {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
rbc.close();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
final JrtFileStore getFileStore(JrtPath path) {
|
||||
return new JrtFileStore(path);
|
||||
}
|
||||
|
||||
final void ensureOpen() throws IOException {
|
||||
if (!isOpen()) {
|
||||
throw new ClosedFileSystemException();
|
||||
}
|
||||
}
|
||||
|
||||
final JrtPath getRootPath() {
|
||||
return rootPath;
|
||||
}
|
||||
|
||||
boolean isSameFile(JrtPath path1, JrtPath path2) throws IOException {
|
||||
return checkNode(path1) == checkNode(path2);
|
||||
}
|
||||
|
||||
boolean isLink(JrtPath path) throws IOException {
|
||||
return checkNode(path).isLink();
|
||||
}
|
||||
|
||||
boolean exists(JrtPath path) throws IOException {
|
||||
try {
|
||||
checkNode(path);
|
||||
} catch (NoSuchFileException exp) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean isDirectory(JrtPath path, boolean resolveLinks)
|
||||
throws IOException {
|
||||
Node node = checkNode(path);
|
||||
return resolveLinks && node.isLink()
|
||||
? node.resolveLink(true).isDirectory()
|
||||
: node.isDirectory();
|
||||
}
|
||||
|
||||
JrtPath toRealPath(JrtPath path, LinkOption... options)
|
||||
throws IOException {
|
||||
Node node = checkNode(path);
|
||||
if (followLinks(options) && node.isLink()) {
|
||||
node = node.resolveLink();
|
||||
}
|
||||
// image node holds the real/absolute path name
|
||||
return new JrtPath(this, node.getName(), true);
|
||||
}
|
||||
|
||||
private Node lookup(String path) {
|
||||
try {
|
||||
return image.findNode(path);
|
||||
} catch (RuntimeException | IOException ex) {
|
||||
throw new InvalidPathException(path, ex.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private Node lookupSymbolic(String path) {
|
||||
int i = 1;
|
||||
while (i < path.length()) {
|
||||
i = path.indexOf('/', i);
|
||||
if (i == -1) {
|
||||
break;
|
||||
}
|
||||
String prefix = path.substring(0, i);
|
||||
Node node = lookup(prefix);
|
||||
if (node == null) {
|
||||
break;
|
||||
}
|
||||
if (node.isLink()) {
|
||||
Node link = node.resolveLink(true);
|
||||
// resolved symbolic path concatenated to the rest of the path
|
||||
String resPath = link.getName() + path.substring(i);
|
||||
node = lookup(resPath);
|
||||
return node != null ? node : lookupSymbolic(resPath);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Node checkNode(JrtPath path) throws IOException {
|
||||
ensureOpen();
|
||||
String p = path.getResolvedPath();
|
||||
Node node = lookup(p);
|
||||
if (node == null) {
|
||||
node = lookupSymbolic(p);
|
||||
if (node == null) {
|
||||
throw new NoSuchFileException(p);
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
}
|
||||
+357
@@ -0,0 +1,357 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javac.internal.jrtfs;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.channels.*;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.DirectoryStream.Filter;
|
||||
import java.nio.file.attribute.*;
|
||||
import java.nio.file.spi.FileSystemProvider;
|
||||
import java.net.URI;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
/**
|
||||
* File system provider for jrt file systems. Conditionally creates jrt fs on
|
||||
* .jimage file or exploded modules directory of underlying JDK.
|
||||
*
|
||||
* @implNote This class needs to maintain JDK 8 source compatibility.
|
||||
*
|
||||
* It is used internally in the JDK to implement jimage/jrtfs access,
|
||||
* but also compiled and delivered as part of the jrtfs.jar to support access
|
||||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
public final class JrtFileSystemProvider extends FileSystemProvider {
|
||||
|
||||
private volatile FileSystem theFileSystem;
|
||||
|
||||
public JrtFileSystemProvider() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getScheme() {
|
||||
return "jrt";
|
||||
}
|
||||
|
||||
/**
|
||||
* Need RuntimePermission "accessSystemModules" to create or get jrt:/
|
||||
*/
|
||||
private void checkPermission() {
|
||||
@SuppressWarnings("removal")
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
RuntimePermission perm = new RuntimePermission("accessSystemModules");
|
||||
sm.checkPermission(perm);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkUri(URI uri) {
|
||||
if (!uri.getScheme().equalsIgnoreCase(getScheme())) {
|
||||
throw new IllegalArgumentException("URI does not match this provider");
|
||||
}
|
||||
if (uri.getAuthority() != null) {
|
||||
throw new IllegalArgumentException("Authority component present");
|
||||
}
|
||||
if (uri.getPath() == null) {
|
||||
throw new IllegalArgumentException("Path component is undefined");
|
||||
}
|
||||
if (!uri.getPath().equals("/")) {
|
||||
throw new IllegalArgumentException("Path component should be '/'");
|
||||
}
|
||||
if (uri.getQuery() != null) {
|
||||
throw new IllegalArgumentException("Query component present");
|
||||
}
|
||||
if (uri.getFragment() != null) {
|
||||
throw new IllegalArgumentException("Fragment component present");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileSystem newFileSystem(URI uri, Map<String, ?> env)
|
||||
throws IOException {
|
||||
Objects.requireNonNull(env);
|
||||
checkPermission();
|
||||
checkUri(uri);
|
||||
|
||||
// ANDROIDIDE-CHANGED: Do not check for java.home property and directly return new file system instance.
|
||||
return new JrtFileSystem(this, env);
|
||||
}
|
||||
|
||||
private static final String JRT_FS_JAR = "jrt-fs.jar";
|
||||
private FileSystem newFileSystem(String targetHome, URI uri, Map<String, ?> env)
|
||||
throws IOException {
|
||||
Objects.requireNonNull(targetHome);
|
||||
Path jrtfs = FileSystems.getDefault().getPath(targetHome, "lib", JRT_FS_JAR);
|
||||
if (Files.notExists(jrtfs)) {
|
||||
throw new IOException(jrtfs.toString() + " not exist");
|
||||
}
|
||||
Map<String,?> newEnv = new HashMap<>(env);
|
||||
newEnv.remove("java.home");
|
||||
ClassLoader cl = newJrtFsLoader(jrtfs);
|
||||
try {
|
||||
Class<?> c = Class.forName(JrtFileSystemProvider.class.getName(), false, cl);
|
||||
@SuppressWarnings("deprecation")
|
||||
Object tmp = c.newInstance();
|
||||
return ((FileSystemProvider)tmp).newFileSystem(uri, newEnv);
|
||||
} catch (ClassNotFoundException |
|
||||
IllegalAccessException |
|
||||
InstantiationException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static class JrtFsLoader extends URLClassLoader {
|
||||
JrtFsLoader(URL[] urls) {
|
||||
super(urls);
|
||||
}
|
||||
@Override
|
||||
protected Class<?> loadClass(String cn, boolean resolve)
|
||||
throws ClassNotFoundException
|
||||
{
|
||||
Class<?> c = findLoadedClass(cn);
|
||||
if (c == null) {
|
||||
URL u = findResource(cn.replace('.', '/') + ".class");
|
||||
if (u != null) {
|
||||
c = findClass(cn);
|
||||
} else {
|
||||
return super.loadClass(cn, resolve);
|
||||
}
|
||||
}
|
||||
if (resolve)
|
||||
resolveClass(c);
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
private static URLClassLoader newJrtFsLoader(Path jrtfs) {
|
||||
final URL url;
|
||||
try {
|
||||
url = jrtfs.toUri().toURL();
|
||||
} catch (MalformedURLException mue) {
|
||||
throw new IllegalArgumentException(mue);
|
||||
}
|
||||
|
||||
final URL[] urls = new URL[] { url };
|
||||
return AccessController.doPrivileged(
|
||||
new PrivilegedAction<URLClassLoader>() {
|
||||
@Override
|
||||
public URLClassLoader run() {
|
||||
return new JrtFsLoader(urls);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getPath(URI uri) {
|
||||
checkPermission();
|
||||
if (!uri.getScheme().equalsIgnoreCase(getScheme())) {
|
||||
throw new IllegalArgumentException("URI does not match this provider");
|
||||
}
|
||||
if (uri.getAuthority() != null) {
|
||||
throw new IllegalArgumentException("Authority component present");
|
||||
}
|
||||
if (uri.getQuery() != null) {
|
||||
throw new IllegalArgumentException("Query component present");
|
||||
}
|
||||
if (uri.getFragment() != null) {
|
||||
throw new IllegalArgumentException("Fragment component present");
|
||||
}
|
||||
String path = uri.getPath();
|
||||
if (path == null || path.charAt(0) != '/' || path.contains("..")) {
|
||||
throw new IllegalArgumentException("Invalid path component");
|
||||
}
|
||||
|
||||
return getTheFileSystem().getPath("/modules" + path);
|
||||
}
|
||||
|
||||
private FileSystem getTheFileSystem() {
|
||||
checkPermission();
|
||||
FileSystem fs = this.theFileSystem;
|
||||
if (fs == null) {
|
||||
synchronized (this) {
|
||||
fs = this.theFileSystem;
|
||||
if (fs == null) {
|
||||
try {
|
||||
this.theFileSystem = fs = new JrtFileSystem(this, null);
|
||||
} catch (IOException ioe) {
|
||||
throw new InternalError(ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return fs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileSystem getFileSystem(URI uri) {
|
||||
checkPermission();
|
||||
checkUri(uri);
|
||||
return getTheFileSystem();
|
||||
}
|
||||
|
||||
// Checks that the given file is a JrtPath
|
||||
static final JrtPath toJrtPath(Path path) {
|
||||
Objects.requireNonNull(path, "path");
|
||||
if (!(path instanceof JrtPath)) {
|
||||
throw new ProviderMismatchException();
|
||||
}
|
||||
return (JrtPath) path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkAccess(Path path, AccessMode... modes) throws IOException {
|
||||
toJrtPath(path).checkAccess(modes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path readSymbolicLink(Path link) throws IOException {
|
||||
return toJrtPath(link).readSymbolicLink();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copy(Path src, Path target, CopyOption... options)
|
||||
throws IOException {
|
||||
toJrtPath(src).copy(toJrtPath(target), options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createDirectory(Path path, FileAttribute<?>... attrs)
|
||||
throws IOException {
|
||||
toJrtPath(path).createDirectory(attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void delete(Path path) throws IOException {
|
||||
toJrtPath(path).delete();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <V extends FileAttributeView> V
|
||||
getFileAttributeView(Path path, Class<V> type, LinkOption... options) {
|
||||
return JrtFileAttributeView.get(toJrtPath(path), type, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileStore getFileStore(Path path) throws IOException {
|
||||
return toJrtPath(path).getFileStore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHidden(Path path) {
|
||||
return toJrtPath(path).isHidden();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameFile(Path path, Path other) throws IOException {
|
||||
return toJrtPath(path).isSameFile(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move(Path src, Path target, CopyOption... options)
|
||||
throws IOException {
|
||||
toJrtPath(src).move(toJrtPath(target), options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousFileChannel newAsynchronousFileChannel(Path path,
|
||||
Set<? extends OpenOption> options,
|
||||
ExecutorService exec,
|
||||
FileAttribute<?>... attrs)
|
||||
throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SeekableByteChannel newByteChannel(Path path,
|
||||
Set<? extends OpenOption> options,
|
||||
FileAttribute<?>... attrs)
|
||||
throws IOException {
|
||||
return toJrtPath(path).newByteChannel(options, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DirectoryStream<Path> newDirectoryStream(
|
||||
Path path, Filter<? super Path> filter) throws IOException {
|
||||
return toJrtPath(path).newDirectoryStream(filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileChannel newFileChannel(Path path,
|
||||
Set<? extends OpenOption> options,
|
||||
FileAttribute<?>... attrs)
|
||||
throws IOException {
|
||||
return toJrtPath(path).newFileChannel(options, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream newInputStream(Path path, OpenOption... options)
|
||||
throws IOException {
|
||||
return toJrtPath(path).newInputStream(options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream newOutputStream(Path path, OpenOption... options)
|
||||
throws IOException {
|
||||
return toJrtPath(path).newOutputStream(options);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked") // Cast to A
|
||||
public <A extends BasicFileAttributes> A
|
||||
readAttributes(Path path, Class<A> type, LinkOption... options)
|
||||
throws IOException {
|
||||
if (type == BasicFileAttributes.class || type == JrtFileAttributes.class) {
|
||||
return (A) toJrtPath(path).getAttributes(options);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object>
|
||||
readAttributes(Path path, String attribute, LinkOption... options)
|
||||
throws IOException {
|
||||
return toJrtPath(path).readAttributes(attribute, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(Path path, String attribute,
|
||||
Object value, LinkOption... options)
|
||||
throws IOException {
|
||||
toJrtPath(path).setAttribute(attribute, value, options);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,955 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javac.internal.jrtfs;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOError;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.SeekableByteChannel;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.DirectoryStream.Filter;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.nio.file.attribute.BasicFileAttributeView;
|
||||
import java.nio.file.attribute.FileAttribute;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import static java.nio.file.StandardOpenOption.*;
|
||||
import static java.nio.file.StandardCopyOption.*;
|
||||
|
||||
/**
|
||||
* Base class for Path implementation of jrt file systems.
|
||||
*
|
||||
* @implNote This class needs to maintain JDK 8 source compatibility.
|
||||
*
|
||||
* It is used internally in the JDK to implement jimage/jrtfs access,
|
||||
* but also compiled and delivered as part of the jrtfs.jar to support access
|
||||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
final class JrtPath implements Path {
|
||||
|
||||
final JrtFileSystem jrtfs;
|
||||
private final String path;
|
||||
private volatile int[] offsets;
|
||||
|
||||
JrtPath(JrtFileSystem jrtfs, String path) {
|
||||
this.jrtfs = jrtfs;
|
||||
this.path = normalize(path);
|
||||
this.resolved = null;
|
||||
}
|
||||
|
||||
JrtPath(JrtFileSystem jrtfs, String path, boolean normalized) {
|
||||
this.jrtfs = jrtfs;
|
||||
this.path = normalized ? path : normalize(path);
|
||||
this.resolved = null;
|
||||
}
|
||||
|
||||
final String getName() {
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final JrtPath getRoot() {
|
||||
if (this.isAbsolute()) {
|
||||
return jrtfs.getRootPath();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final JrtPath getFileName() {
|
||||
if (path.isEmpty())
|
||||
return this;
|
||||
if (path.length() == 1 && path.charAt(0) == '/')
|
||||
return null;
|
||||
int off = path.lastIndexOf('/');
|
||||
if (off == -1)
|
||||
return this;
|
||||
return new JrtPath(jrtfs, path.substring(off + 1), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final JrtPath getParent() {
|
||||
initOffsets();
|
||||
int count = offsets.length;
|
||||
if (count == 0) { // no elements so no parent
|
||||
return null;
|
||||
}
|
||||
int off = offsets[count - 1] - 1;
|
||||
if (off <= 0) { // parent is root only (may be null)
|
||||
return getRoot();
|
||||
}
|
||||
return new JrtPath(jrtfs, path.substring(0, off));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getNameCount() {
|
||||
initOffsets();
|
||||
return offsets.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final JrtPath getName(int index) {
|
||||
initOffsets();
|
||||
if (index < 0 || index >= offsets.length) {
|
||||
throw new IllegalArgumentException("index: " +
|
||||
index + ", offsets length: " + offsets.length);
|
||||
}
|
||||
int begin = offsets[index];
|
||||
int end;
|
||||
if (index == (offsets.length - 1)) {
|
||||
end = path.length();
|
||||
} else {
|
||||
end = offsets[index + 1];
|
||||
}
|
||||
return new JrtPath(jrtfs, path.substring(begin, end));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final JrtPath subpath(int beginIndex, int endIndex) {
|
||||
initOffsets();
|
||||
if (beginIndex < 0 || endIndex > offsets.length ||
|
||||
beginIndex >= endIndex) {
|
||||
throw new IllegalArgumentException(
|
||||
"beginIndex: " + beginIndex + ", endIndex: " + endIndex +
|
||||
", offsets length: " + offsets.length);
|
||||
}
|
||||
// starting/ending offsets
|
||||
int begin = offsets[beginIndex];
|
||||
int end;
|
||||
if (endIndex == offsets.length) {
|
||||
end = path.length();
|
||||
} else {
|
||||
end = offsets[endIndex];
|
||||
}
|
||||
return new JrtPath(jrtfs, path.substring(begin, end));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final JrtPath toRealPath(LinkOption... options) throws IOException {
|
||||
return jrtfs.toRealPath(this, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final JrtPath toAbsolutePath() {
|
||||
if (isAbsolute())
|
||||
return this;
|
||||
return new JrtPath(jrtfs, "/" + path, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final URI toUri() {
|
||||
String p = toAbsolutePath().path;
|
||||
if (!p.startsWith("/modules") || p.contains("..")) {
|
||||
throw new IOError(new RuntimeException(p + " cannot be represented as URI"));
|
||||
}
|
||||
|
||||
p = p.substring("/modules".length());
|
||||
if (p.isEmpty()) {
|
||||
p = "/";
|
||||
}
|
||||
return toUri(p);
|
||||
}
|
||||
|
||||
private boolean equalsNameAt(JrtPath other, int index) {
|
||||
int mbegin = offsets[index];
|
||||
int mlen;
|
||||
if (index == (offsets.length - 1)) {
|
||||
mlen = path.length() - mbegin;
|
||||
} else {
|
||||
mlen = offsets[index + 1] - mbegin - 1;
|
||||
}
|
||||
int obegin = other.offsets[index];
|
||||
int olen;
|
||||
if (index == (other.offsets.length - 1)) {
|
||||
olen = other.path.length() - obegin;
|
||||
} else {
|
||||
olen = other.offsets[index + 1] - obegin - 1;
|
||||
}
|
||||
if (mlen != olen) {
|
||||
return false;
|
||||
}
|
||||
int n = 0;
|
||||
while (n < mlen) {
|
||||
if (path.charAt(mbegin + n) != other.path.charAt(obegin + n)) {
|
||||
return false;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final JrtPath relativize(Path other) {
|
||||
final JrtPath o = checkPath(other);
|
||||
if (o.equals(this)) {
|
||||
return new JrtPath(jrtfs, "", true);
|
||||
}
|
||||
if (path.isEmpty()) {
|
||||
return o;
|
||||
}
|
||||
if (jrtfs != o.jrtfs || isAbsolute() != o.isAbsolute()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Incorrect filesystem or path: " + other);
|
||||
}
|
||||
final String tp = this.path;
|
||||
final String op = o.path;
|
||||
if (op.startsWith(tp)) { // fast path
|
||||
int off = tp.length();
|
||||
if (op.charAt(off - 1) == '/')
|
||||
return new JrtPath(jrtfs, op.substring(off), true);
|
||||
if (op.charAt(off) == '/')
|
||||
return new JrtPath(jrtfs, op.substring(off + 1), true);
|
||||
}
|
||||
int mc = this.getNameCount();
|
||||
int oc = o.getNameCount();
|
||||
int n = Math.min(mc, oc);
|
||||
int i = 0;
|
||||
while (i < n) {
|
||||
if (!equalsNameAt(o, i)) {
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
int dotdots = mc - i;
|
||||
int len = dotdots * 3 - 1;
|
||||
if (i < oc) {
|
||||
len += (o.path.length() - o.offsets[i] + 1);
|
||||
}
|
||||
StringBuilder sb = new StringBuilder(len);
|
||||
while (dotdots > 0) {
|
||||
sb.append("..");
|
||||
if (sb.length() < len) { // no tailing slash at the end
|
||||
sb.append('/');
|
||||
}
|
||||
dotdots--;
|
||||
}
|
||||
if (i < oc) {
|
||||
sb.append(o.path, o.offsets[i], o.path.length());
|
||||
}
|
||||
return new JrtPath(jrtfs, sb.toString(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JrtFileSystem getFileSystem() {
|
||||
return jrtfs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isAbsolute() {
|
||||
return !path.isEmpty() && path.charAt(0) == '/';
|
||||
}
|
||||
|
||||
@Override
|
||||
public final JrtPath resolve(Path other) {
|
||||
final JrtPath o = checkPath(other);
|
||||
if (this.path.isEmpty() || o.isAbsolute()) {
|
||||
return o;
|
||||
}
|
||||
if (o.path.isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder(path.length() + o.path.length() + 1);
|
||||
sb.append(path);
|
||||
if (path.charAt(path.length() - 1) != '/')
|
||||
sb.append('/');
|
||||
sb.append(o.path);
|
||||
return new JrtPath(jrtfs, sb.toString(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Path resolveSibling(Path other) {
|
||||
Objects.requireNonNull(other, "other");
|
||||
Path parent = getParent();
|
||||
return (parent == null) ? other : parent.resolve(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean startsWith(Path other) {
|
||||
if (!(Objects.requireNonNull(other) instanceof JrtPath))
|
||||
return false;
|
||||
final JrtPath o = (JrtPath)other;
|
||||
final String tp = this.path;
|
||||
final String op = o.path;
|
||||
if (isAbsolute() != o.isAbsolute() || !tp.startsWith(op)) {
|
||||
return false;
|
||||
}
|
||||
int off = op.length();
|
||||
if (off == 0) {
|
||||
return tp.isEmpty();
|
||||
}
|
||||
// check match is on name boundary
|
||||
return tp.length() == off || tp.charAt(off) == '/' ||
|
||||
off == 0 || op.charAt(off - 1) == '/';
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean endsWith(Path other) {
|
||||
if (!(Objects.requireNonNull(other) instanceof JrtPath))
|
||||
return false;
|
||||
final JrtPath o = (JrtPath)other;
|
||||
final JrtPath t = this;
|
||||
int olast = o.path.length() - 1;
|
||||
if (olast > 0 && o.path.charAt(olast) == '/') {
|
||||
olast--;
|
||||
}
|
||||
int last = t.path.length() - 1;
|
||||
if (last > 0 && t.path.charAt(last) == '/') {
|
||||
last--;
|
||||
}
|
||||
if (olast == -1) { // o.path.length == 0
|
||||
return last == -1;
|
||||
}
|
||||
if ((o.isAbsolute() && (!t.isAbsolute() || olast != last))
|
||||
|| last < olast) {
|
||||
return false;
|
||||
}
|
||||
for (; olast >= 0; olast--, last--) {
|
||||
if (o.path.charAt(olast) != t.path.charAt(last)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return o.path.charAt(olast + 1) == '/' ||
|
||||
last == -1 || t.path.charAt(last) == '/';
|
||||
}
|
||||
|
||||
@Override
|
||||
public final JrtPath resolve(String other) {
|
||||
return resolve(getFileSystem().getPath(other));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Path resolveSibling(String other) {
|
||||
return resolveSibling(getFileSystem().getPath(other));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean startsWith(String other) {
|
||||
return startsWith(getFileSystem().getPath(other));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean endsWith(String other) {
|
||||
return endsWith(getFileSystem().getPath(other));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final JrtPath normalize() {
|
||||
String res = getResolved();
|
||||
if (res == path) { // no change
|
||||
return this;
|
||||
}
|
||||
return new JrtPath(jrtfs, res, true);
|
||||
}
|
||||
|
||||
private JrtPath checkPath(Path path) {
|
||||
Objects.requireNonNull(path);
|
||||
if (!(path instanceof JrtPath))
|
||||
throw new ProviderMismatchException("path class: " +
|
||||
path.getClass());
|
||||
return (JrtPath) path;
|
||||
}
|
||||
|
||||
// create offset list if not already created
|
||||
private void initOffsets() {
|
||||
if (this.offsets == null) {
|
||||
int len = path.length();
|
||||
// count names
|
||||
int count = 0;
|
||||
int off = 0;
|
||||
while (off < len) {
|
||||
char c = path.charAt(off++);
|
||||
if (c != '/') {
|
||||
count++;
|
||||
off = path.indexOf('/', off);
|
||||
if (off == -1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
// populate offsets
|
||||
int[] offsets = new int[count];
|
||||
count = 0;
|
||||
off = 0;
|
||||
while (off < len) {
|
||||
char c = path.charAt(off);
|
||||
if (c == '/') {
|
||||
off++;
|
||||
} else {
|
||||
offsets[count++] = off++;
|
||||
off = path.indexOf('/', off);
|
||||
if (off == -1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.offsets = offsets;
|
||||
}
|
||||
}
|
||||
|
||||
private volatile String resolved;
|
||||
|
||||
final String getResolvedPath() {
|
||||
String r = resolved;
|
||||
if (r == null) {
|
||||
if (isAbsolute()) {
|
||||
r = getResolved();
|
||||
} else {
|
||||
r = toAbsolutePath().getResolvedPath();
|
||||
}
|
||||
resolved = r;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
// removes redundant slashs, replace "\" to separator "/"
|
||||
// and check for invalid characters
|
||||
private static String normalize(String path) {
|
||||
int len = path.length();
|
||||
if (len == 0) {
|
||||
return path;
|
||||
}
|
||||
char prevC = 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
char c = path.charAt(i);
|
||||
if (c == '\\' || c == '\u0000') {
|
||||
return normalize(path, i);
|
||||
}
|
||||
if (c == '/' && prevC == '/') {
|
||||
return normalize(path, i - 1);
|
||||
}
|
||||
prevC = c;
|
||||
}
|
||||
if (prevC == '/' && len > 1) {
|
||||
return path.substring(0, len - 1);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
private static String normalize(String path, int off) {
|
||||
int len = path.length();
|
||||
StringBuilder to = new StringBuilder(len);
|
||||
to.append(path, 0, off);
|
||||
char prevC = 0;
|
||||
while (off < len) {
|
||||
char c = path.charAt(off++);
|
||||
if (c == '\\') {
|
||||
c = '/';
|
||||
}
|
||||
if (c == '/' && prevC == '/') {
|
||||
continue;
|
||||
}
|
||||
if (c == '\u0000') {
|
||||
throw new InvalidPathException(path,
|
||||
"Path: NUL character not allowed");
|
||||
}
|
||||
to.append(c);
|
||||
prevC = c;
|
||||
}
|
||||
len = to.length();
|
||||
if (len > 1 && to.charAt(len - 1) == '/') {
|
||||
to.deleteCharAt(len - 1);
|
||||
}
|
||||
return to.toString();
|
||||
}
|
||||
|
||||
// Remove DotSlash(./) and resolve DotDot (..) components
|
||||
private String getResolved() {
|
||||
int length = path.length();
|
||||
if (length == 0 || (path.indexOf("./") == -1 && path.charAt(length - 1) != '.')) {
|
||||
return path;
|
||||
} else {
|
||||
return resolvePath();
|
||||
}
|
||||
}
|
||||
|
||||
private String resolvePath() {
|
||||
int length = path.length();
|
||||
char[] to = new char[length];
|
||||
int nc = getNameCount();
|
||||
int[] lastM = new int[nc];
|
||||
int lastMOff = -1;
|
||||
int m = 0;
|
||||
for (int i = 0; i < nc; i++) {
|
||||
int n = offsets[i];
|
||||
int len = (i == offsets.length - 1) ? length - n
|
||||
: offsets[i + 1] - n - 1;
|
||||
if (len == 1 && path.charAt(n) == '.') {
|
||||
if (m == 0 && path.charAt(0) == '/') // absolute path
|
||||
to[m++] = '/';
|
||||
continue;
|
||||
}
|
||||
if (len == 2 && path.charAt(n) == '.' && path.charAt(n + 1) == '.') {
|
||||
if (lastMOff >= 0) {
|
||||
m = lastM[lastMOff--]; // retreat
|
||||
continue;
|
||||
}
|
||||
if (path.charAt(0) == '/') { // "/../xyz" skip
|
||||
if (m == 0)
|
||||
to[m++] = '/';
|
||||
} else { // "../xyz" -> "../xyz"
|
||||
if (m != 0 && to[m-1] != '/')
|
||||
to[m++] = '/';
|
||||
while (len-- > 0)
|
||||
to[m++] = path.charAt(n++);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (m == 0 && path.charAt(0) == '/' || // absolute path
|
||||
m != 0 && to[m-1] != '/') { // not the first name
|
||||
to[m++] = '/';
|
||||
}
|
||||
lastM[++lastMOff] = m;
|
||||
while (len-- > 0)
|
||||
to[m++] = path.charAt(n++);
|
||||
}
|
||||
if (m > 1 && to[m - 1] == '/')
|
||||
m--;
|
||||
return (m == to.length) ? new String(to) : new String(to, 0, m);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String toString() {
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return path.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean equals(Object obj) {
|
||||
return obj instanceof JrtPath &&
|
||||
this.path.equals(((JrtPath) obj).path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int compareTo(Path other) {
|
||||
final JrtPath o = checkPath(other);
|
||||
return path.compareTo(o.path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WatchKey register(
|
||||
WatchService watcher,
|
||||
WatchEvent.Kind<?>[] events,
|
||||
WatchEvent.Modifier... modifiers) {
|
||||
Objects.requireNonNull(watcher, "watcher");
|
||||
Objects.requireNonNull(events, "events");
|
||||
Objects.requireNonNull(modifiers, "modifiers");
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WatchKey register(WatchService watcher, WatchEvent.Kind<?>... events) {
|
||||
return register(watcher, events, new WatchEvent.Modifier[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final File toFile() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Iterator<Path> iterator() {
|
||||
return new Iterator<Path>() {
|
||||
private int i = 0;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return (i < getNameCount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path next() {
|
||||
if (i < getNameCount()) {
|
||||
Path result = getName(i);
|
||||
i++;
|
||||
return result;
|
||||
} else {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new ReadOnlyFileSystemException();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Helpers for JrtFileSystemProvider and JrtFileSystem
|
||||
|
||||
final JrtPath readSymbolicLink() throws IOException {
|
||||
if (!jrtfs.isLink(this)) {
|
||||
throw new IOException("not a symbolic link");
|
||||
}
|
||||
return jrtfs.resolveLink(this);
|
||||
}
|
||||
|
||||
final boolean isHidden() {
|
||||
return false;
|
||||
}
|
||||
|
||||
final void createDirectory(FileAttribute<?>... attrs)
|
||||
throws IOException {
|
||||
jrtfs.createDirectory(this, attrs);
|
||||
}
|
||||
|
||||
final InputStream newInputStream(OpenOption... options) throws IOException {
|
||||
if (options.length > 0) {
|
||||
for (OpenOption opt : options) {
|
||||
if (opt != READ) {
|
||||
throw new UnsupportedOperationException("'" + opt + "' not allowed");
|
||||
}
|
||||
}
|
||||
}
|
||||
return jrtfs.newInputStream(this);
|
||||
}
|
||||
|
||||
final DirectoryStream<Path> newDirectoryStream(Filter<? super Path> filter)
|
||||
throws IOException {
|
||||
return new JrtDirectoryStream(this, filter);
|
||||
}
|
||||
|
||||
final void delete() throws IOException {
|
||||
jrtfs.deleteFile(this, true);
|
||||
}
|
||||
|
||||
final void deleteIfExists() throws IOException {
|
||||
jrtfs.deleteFile(this, false);
|
||||
}
|
||||
|
||||
final JrtFileAttributes getAttributes(LinkOption... options) throws IOException {
|
||||
JrtFileAttributes zfas = jrtfs.getFileAttributes(this, options);
|
||||
if (zfas == null) {
|
||||
throw new NoSuchFileException(toString());
|
||||
}
|
||||
return zfas;
|
||||
}
|
||||
|
||||
final void setAttribute(String attribute, Object value, LinkOption... options)
|
||||
throws IOException {
|
||||
JrtFileAttributeView.setAttribute(this, attribute, value);
|
||||
}
|
||||
|
||||
final Map<String, Object> readAttributes(String attributes, LinkOption... options)
|
||||
throws IOException {
|
||||
return JrtFileAttributeView.readAttributes(this, attributes, options);
|
||||
}
|
||||
|
||||
final void setTimes(FileTime mtime, FileTime atime, FileTime ctime)
|
||||
throws IOException {
|
||||
jrtfs.setTimes(this, mtime, atime, ctime);
|
||||
}
|
||||
|
||||
final FileStore getFileStore() throws IOException {
|
||||
// each JrtFileSystem only has one root (as requested for now)
|
||||
if (exists()) {
|
||||
return jrtfs.getFileStore(this);
|
||||
}
|
||||
throw new NoSuchFileException(path);
|
||||
}
|
||||
|
||||
final boolean isSameFile(Path other) throws IOException {
|
||||
if (this == other || this.equals(other)) {
|
||||
return true;
|
||||
}
|
||||
if (other == null || this.getFileSystem() != other.getFileSystem()) {
|
||||
return false;
|
||||
}
|
||||
this.checkAccess();
|
||||
JrtPath o = (JrtPath) other;
|
||||
o.checkAccess();
|
||||
return this.getResolvedPath().equals(o.getResolvedPath()) ||
|
||||
jrtfs.isSameFile(this, o);
|
||||
}
|
||||
|
||||
final SeekableByteChannel newByteChannel(Set<? extends OpenOption> options,
|
||||
FileAttribute<?>... attrs)
|
||||
throws IOException
|
||||
{
|
||||
return jrtfs.newByteChannel(this, options, attrs);
|
||||
}
|
||||
|
||||
final FileChannel newFileChannel(Set<? extends OpenOption> options,
|
||||
FileAttribute<?>... attrs)
|
||||
throws IOException {
|
||||
return jrtfs.newFileChannel(this, options, attrs);
|
||||
}
|
||||
|
||||
final void checkAccess(AccessMode... modes) throws IOException {
|
||||
if (modes.length == 0) { // check if the path exists
|
||||
jrtfs.checkNode(this); // no need to follow link. the "link" node
|
||||
// is built from real node under "/module"
|
||||
} else {
|
||||
boolean w = false;
|
||||
for (AccessMode mode : modes) {
|
||||
switch (mode) {
|
||||
case READ:
|
||||
break;
|
||||
case WRITE:
|
||||
w = true;
|
||||
break;
|
||||
case EXECUTE:
|
||||
throw new AccessDeniedException(toString());
|
||||
default:
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
jrtfs.checkNode(this);
|
||||
if (w && jrtfs.isReadOnly()) {
|
||||
throw new AccessDeniedException(toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final boolean exists() {
|
||||
try {
|
||||
return jrtfs.exists(this);
|
||||
} catch (IOException x) {}
|
||||
return false;
|
||||
}
|
||||
|
||||
final OutputStream newOutputStream(OpenOption... options) throws IOException {
|
||||
if (options.length == 0) {
|
||||
return jrtfs.newOutputStream(this, CREATE_NEW, WRITE);
|
||||
}
|
||||
return jrtfs.newOutputStream(this, options);
|
||||
}
|
||||
|
||||
final void move(JrtPath target, CopyOption... options) throws IOException {
|
||||
if (this.jrtfs == target.jrtfs) {
|
||||
jrtfs.copyFile(true, this, target, options);
|
||||
} else {
|
||||
copyToTarget(target, options);
|
||||
delete();
|
||||
}
|
||||
}
|
||||
|
||||
final void copy(JrtPath target, CopyOption... options) throws IOException {
|
||||
if (this.jrtfs == target.jrtfs) {
|
||||
jrtfs.copyFile(false, this, target, options);
|
||||
} else {
|
||||
copyToTarget(target, options);
|
||||
}
|
||||
}
|
||||
|
||||
private void copyToTarget(JrtPath target, CopyOption... options)
|
||||
throws IOException {
|
||||
boolean replaceExisting = false;
|
||||
boolean copyAttrs = false;
|
||||
for (CopyOption opt : options) {
|
||||
if (opt == REPLACE_EXISTING) {
|
||||
replaceExisting = true;
|
||||
} else if (opt == COPY_ATTRIBUTES) {
|
||||
copyAttrs = true;
|
||||
}
|
||||
}
|
||||
// attributes of source file
|
||||
BasicFileAttributes jrtfas = getAttributes();
|
||||
// check if target exists
|
||||
boolean exists;
|
||||
if (replaceExisting) {
|
||||
try {
|
||||
target.deleteIfExists();
|
||||
exists = false;
|
||||
} catch (DirectoryNotEmptyException x) {
|
||||
exists = true;
|
||||
}
|
||||
} else {
|
||||
exists = target.exists();
|
||||
}
|
||||
if (exists) {
|
||||
throw new FileAlreadyExistsException(target.toString());
|
||||
}
|
||||
if (jrtfas.isDirectory()) {
|
||||
// create directory or file
|
||||
target.createDirectory();
|
||||
} else {
|
||||
try (InputStream is = jrtfs.newInputStream(this);
|
||||
OutputStream os = target.newOutputStream()) {
|
||||
byte[] buf = new byte[8192];
|
||||
int n;
|
||||
while ((n = is.read(buf)) != -1) {
|
||||
os.write(buf, 0, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (copyAttrs) {
|
||||
BasicFileAttributeView view =
|
||||
Files.getFileAttributeView(target, BasicFileAttributeView.class);
|
||||
try {
|
||||
view.setTimes(jrtfas.lastModifiedTime(),
|
||||
jrtfas.lastAccessTime(),
|
||||
jrtfas.creationTime());
|
||||
} catch (IOException x) {
|
||||
try {
|
||||
target.delete(); // rollback?
|
||||
} catch (IOException ignore) {}
|
||||
throw x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// adopted from sun.nio.fs.UnixUriUtils
|
||||
private static URI toUri(String str) {
|
||||
char[] path = str.toCharArray();
|
||||
assert path[0] == '/';
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(path[0]);
|
||||
for (int i = 1; i < path.length; i++) {
|
||||
char c = (char)(path[i] & 0xff);
|
||||
if (match(c, L_PATH, H_PATH)) {
|
||||
sb.append(c);
|
||||
} else {
|
||||
sb.append('%');
|
||||
sb.append(hexDigits[(c >> 4) & 0x0f]);
|
||||
sb.append(hexDigits[(c) & 0x0f]);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return new URI("jrt:" + sb.toString());
|
||||
} catch (URISyntaxException x) {
|
||||
throw new AssertionError(x); // should not happen
|
||||
}
|
||||
}
|
||||
|
||||
// The following is copied from java.net.URI
|
||||
|
||||
// Compute the low-order mask for the characters in the given string
|
||||
private static long lowMask(String chars) {
|
||||
int n = chars.length();
|
||||
long m = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
char c = chars.charAt(i);
|
||||
if (c < 64)
|
||||
m |= (1L << c);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
// Compute the high-order mask for the characters in the given string
|
||||
private static long highMask(String chars) {
|
||||
int n = chars.length();
|
||||
long m = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
char c = chars.charAt(i);
|
||||
if ((c >= 64) && (c < 128))
|
||||
m |= (1L << (c - 64));
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
// Compute a low-order mask for the characters
|
||||
// between first and last, inclusive
|
||||
private static long lowMask(char first, char last) {
|
||||
long m = 0;
|
||||
int f = Math.max(Math.min(first, 63), 0);
|
||||
int l = Math.max(Math.min(last, 63), 0);
|
||||
for (int i = f; i <= l; i++)
|
||||
m |= 1L << i;
|
||||
return m;
|
||||
}
|
||||
|
||||
// Compute a high-order mask for the characters
|
||||
// between first and last, inclusive
|
||||
private static long highMask(char first, char last) {
|
||||
long m = 0;
|
||||
int f = Math.max(Math.min(first, 127), 64) - 64;
|
||||
int l = Math.max(Math.min(last, 127), 64) - 64;
|
||||
for (int i = f; i <= l; i++)
|
||||
m |= 1L << i;
|
||||
return m;
|
||||
}
|
||||
|
||||
// Tell whether the given character is permitted by the given mask pair
|
||||
private static boolean match(char c, long lowMask, long highMask) {
|
||||
if (c < 64)
|
||||
return ((1L << c) & lowMask) != 0;
|
||||
if (c < 128)
|
||||
return ((1L << (c - 64)) & highMask) != 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
|
||||
// "8" | "9"
|
||||
private static final long L_DIGIT = lowMask('0', '9');
|
||||
private static final long H_DIGIT = 0L;
|
||||
|
||||
// upalpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" |
|
||||
// "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" |
|
||||
// "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z"
|
||||
private static final long L_UPALPHA = 0L;
|
||||
private static final long H_UPALPHA = highMask('A', 'Z');
|
||||
|
||||
// lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" |
|
||||
// "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" |
|
||||
// "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"
|
||||
private static final long L_LOWALPHA = 0L;
|
||||
private static final long H_LOWALPHA = highMask('a', 'z');
|
||||
|
||||
// alpha = lowalpha | upalpha
|
||||
private static final long L_ALPHA = L_LOWALPHA | L_UPALPHA;
|
||||
private static final long H_ALPHA = H_LOWALPHA | H_UPALPHA;
|
||||
|
||||
// alphanum = alpha | digit
|
||||
private static final long L_ALPHANUM = L_DIGIT | L_ALPHA;
|
||||
private static final long H_ALPHANUM = H_DIGIT | H_ALPHA;
|
||||
|
||||
// mark = "-" | "_" | "." | "!" | "~" | "*" | "'" |
|
||||
// "(" | ")"
|
||||
private static final long L_MARK = lowMask("-_.!~*'()");
|
||||
private static final long H_MARK = highMask("-_.!~*'()");
|
||||
|
||||
// unreserved = alphanum | mark
|
||||
private static final long L_UNRESERVED = L_ALPHANUM | L_MARK;
|
||||
private static final long H_UNRESERVED = H_ALPHANUM | H_MARK;
|
||||
|
||||
// pchar = unreserved | escaped |
|
||||
// ":" | "@" | "&" | "=" | "+" | "$" | ","
|
||||
private static final long L_PCHAR
|
||||
= L_UNRESERVED | lowMask(":@&=+$,");
|
||||
private static final long H_PCHAR
|
||||
= H_UNRESERVED | highMask(":@&=+$,");
|
||||
|
||||
// All valid path characters
|
||||
private static final long L_PATH = L_PCHAR | lowMask(";/");
|
||||
private static final long H_PATH = H_PCHAR | highMask(";/");
|
||||
|
||||
private static final char[] hexDigits = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javac.internal.jrtfs;
|
||||
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
/**
|
||||
* @implNote This class needs to maintain JDK 8 source compatibility.
|
||||
*
|
||||
* It is used internally in the JDK to implement jimage/jrtfs access,
|
||||
* but also compiled and delivered as part of the jrtfs.jar to support access
|
||||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
final class JrtUtils {
|
||||
private JrtUtils() {}
|
||||
|
||||
private static final String regexMetaChars = ".^$+{[]|()";
|
||||
private static final String globMetaChars = "\\*?[{";
|
||||
private static boolean isRegexMeta(char c) {
|
||||
return regexMetaChars.indexOf(c) != -1;
|
||||
}
|
||||
private static boolean isGlobMeta(char c) {
|
||||
return globMetaChars.indexOf(c) != -1;
|
||||
}
|
||||
private static final char EOL = 0;
|
||||
private static char next(String glob, int i) {
|
||||
if (i < glob.length()) {
|
||||
return glob.charAt(i);
|
||||
}
|
||||
return EOL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a regex pattern from the given glob expression.
|
||||
*
|
||||
* @throws PatternSyntaxException
|
||||
*/
|
||||
public static String toRegexPattern(String globPattern) {
|
||||
boolean inGroup = false;
|
||||
StringBuilder regex = new StringBuilder("^");
|
||||
|
||||
int i = 0;
|
||||
while (i < globPattern.length()) {
|
||||
char c = globPattern.charAt(i++);
|
||||
switch (c) {
|
||||
case '\\':
|
||||
// escape special characters
|
||||
if (i == globPattern.length()) {
|
||||
throw new PatternSyntaxException("No character to escape",
|
||||
globPattern, i - 1);
|
||||
}
|
||||
char next = globPattern.charAt(i++);
|
||||
if (isGlobMeta(next) || isRegexMeta(next)) {
|
||||
regex.append('\\');
|
||||
}
|
||||
regex.append(next);
|
||||
break;
|
||||
case '/':
|
||||
regex.append(c);
|
||||
break;
|
||||
case '[':
|
||||
// don't match name separator in class
|
||||
regex.append("[[^/]&&[");
|
||||
if (next(globPattern, i) == '^') {
|
||||
// escape the regex negation char if it appears
|
||||
regex.append("\\^");
|
||||
i++;
|
||||
} else {
|
||||
// negation
|
||||
if (next(globPattern, i) == '!') {
|
||||
regex.append('^');
|
||||
i++;
|
||||
}
|
||||
// hyphen allowed at start
|
||||
if (next(globPattern, i) == '-') {
|
||||
regex.append('-');
|
||||
i++;
|
||||
}
|
||||
}
|
||||
boolean hasRangeStart = false;
|
||||
char last = 0;
|
||||
while (i < globPattern.length()) {
|
||||
c = globPattern.charAt(i++);
|
||||
if (c == ']') {
|
||||
break;
|
||||
}
|
||||
if (c == '/') {
|
||||
throw new PatternSyntaxException("Explicit 'name separator' in class",
|
||||
globPattern, i - 1);
|
||||
}
|
||||
// TBD: how to specify ']' in a class?
|
||||
if (c == '\\' || c == '[' ||
|
||||
c == '&' && next(globPattern, i) == '&') {
|
||||
// escape '\', '[' or "&&" for regex class
|
||||
regex.append('\\');
|
||||
}
|
||||
regex.append(c);
|
||||
|
||||
if (c == '-') {
|
||||
if (!hasRangeStart) {
|
||||
throw new PatternSyntaxException("Invalid range",
|
||||
globPattern, i - 1);
|
||||
}
|
||||
if ((c = next(globPattern, i++)) == EOL || c == ']') {
|
||||
break;
|
||||
}
|
||||
if (c < last) {
|
||||
throw new PatternSyntaxException("Invalid range",
|
||||
globPattern, i - 3);
|
||||
}
|
||||
regex.append(c);
|
||||
hasRangeStart = false;
|
||||
} else {
|
||||
hasRangeStart = true;
|
||||
last = c;
|
||||
}
|
||||
}
|
||||
if (c != ']') {
|
||||
throw new PatternSyntaxException("Missing ']", globPattern, i - 1);
|
||||
}
|
||||
regex.append("]]");
|
||||
break;
|
||||
case '{':
|
||||
if (inGroup) {
|
||||
throw new PatternSyntaxException("Cannot nest groups",
|
||||
globPattern, i - 1);
|
||||
}
|
||||
regex.append("(?:(?:");
|
||||
inGroup = true;
|
||||
break;
|
||||
case '}':
|
||||
if (inGroup) {
|
||||
regex.append("))");
|
||||
inGroup = false;
|
||||
} else {
|
||||
regex.append('}');
|
||||
}
|
||||
break;
|
||||
case ',':
|
||||
if (inGroup) {
|
||||
regex.append(")|(?:");
|
||||
} else {
|
||||
regex.append(',');
|
||||
}
|
||||
break;
|
||||
case '*':
|
||||
if (next(globPattern, i) == '*') {
|
||||
// crosses directory boundaries
|
||||
regex.append(".*");
|
||||
i++;
|
||||
} else {
|
||||
// within directory boundary
|
||||
regex.append("[^/]*");
|
||||
}
|
||||
break;
|
||||
case '?':
|
||||
regex.append("[^/]");
|
||||
break;
|
||||
default:
|
||||
if (isRegexMeta(c)) {
|
||||
regex.append('\\');
|
||||
}
|
||||
regex.append(c);
|
||||
}
|
||||
}
|
||||
if (inGroup) {
|
||||
throw new PatternSyntaxException("Missing '}", globPattern, i - 1);
|
||||
}
|
||||
return regex.append('$').toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javac.internal.jrtfs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.FileSystemNotFoundException;
|
||||
import java.nio.file.Path;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
import javac.internal.jimage.ImageReader;
|
||||
import javac.internal.jimage.ImageReader.Node;
|
||||
|
||||
import com.itsaky.androidide.config.JavacConfigProvider;
|
||||
|
||||
/**
|
||||
* @implNote This class needs to maintain JDK 8 source compatibility.
|
||||
*
|
||||
* It is used internally in the JDK to implement jimage/jrtfs access,
|
||||
* but also compiled and delivered as part of the jrtfs.jar to support access
|
||||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
abstract class SystemImage {
|
||||
|
||||
abstract Node findNode(String path) throws IOException;
|
||||
abstract byte[] getResource(Node node) throws IOException;
|
||||
abstract void close() throws IOException;
|
||||
|
||||
static SystemImage open() throws IOException {
|
||||
if (modulesImageExists) {
|
||||
// open a .jimage and build directory structure
|
||||
final ImageReader image = ImageReader.open(moduleImageFile);
|
||||
image.getRootDirectory();
|
||||
return new SystemImage() {
|
||||
@Override
|
||||
Node findNode(String path) throws IOException {
|
||||
return image.findNode(path);
|
||||
}
|
||||
@Override
|
||||
byte[] getResource(Node node) throws IOException {
|
||||
return image.getResource(node);
|
||||
}
|
||||
@Override
|
||||
void close() throws IOException {
|
||||
image.close();
|
||||
}
|
||||
};
|
||||
}
|
||||
if (Files.notExists(explodedModulesDir))
|
||||
throw new FileSystemNotFoundException(explodedModulesDir.toString());
|
||||
return new ExplodedImage(explodedModulesDir);
|
||||
}
|
||||
|
||||
static final String RUNTIME_HOME;
|
||||
// "modules" jimage file Path
|
||||
static final Path moduleImageFile;
|
||||
// "modules" jimage exists or not?
|
||||
static final boolean modulesImageExists;
|
||||
// <JAVA_HOME>/modules directory Path
|
||||
static final Path explodedModulesDir;
|
||||
|
||||
static {
|
||||
PrivilegedAction<String> pa = SystemImage::findHome;
|
||||
RUNTIME_HOME = AccessController.doPrivileged(pa);
|
||||
|
||||
FileSystem fs = FileSystems.getDefault();
|
||||
moduleImageFile = fs.getPath(RUNTIME_HOME, "lib", "modules");
|
||||
explodedModulesDir = fs.getPath(RUNTIME_HOME, "modules");
|
||||
|
||||
modulesImageExists = AccessController.doPrivileged(
|
||||
new PrivilegedAction<Boolean>() {
|
||||
@Override
|
||||
public Boolean run() {
|
||||
return Files.isRegularFile(moduleImageFile);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the appropriate JDK home for this usage of the FileSystemProvider.
|
||||
* When the CodeSource is null (null loader) then jrt:/ is the current runtime,
|
||||
* otherwise the JDK home is located relative to jrt-fs.jar.
|
||||
*/
|
||||
private static String findHome() {
|
||||
// AndroidIDE changed: Allow overriding java home.
|
||||
return JavacConfigProvider.getJavaHome();
|
||||
}
|
||||
}
|
||||
+226
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.annotation.processing;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
import jdkx.lang.model.element.*;
|
||||
import jdkx.lang.model.SourceVersion;
|
||||
import jdkx.tools.Diagnostic;
|
||||
|
||||
/**
|
||||
* An abstract annotation processor designed to be a convenient
|
||||
* superclass for most concrete annotation processors. This class
|
||||
* examines annotation values to compute the {@linkplain
|
||||
* #getSupportedOptions options}, {@linkplain
|
||||
* #getSupportedAnnotationTypes annotation interfaces}, and
|
||||
* {@linkplain #getSupportedSourceVersion source version} supported by
|
||||
* its subtypes.
|
||||
*
|
||||
* <p>The getter methods may {@linkplain Messager#printMessage issue
|
||||
* warnings} about noteworthy conditions using the facilities available
|
||||
* after the processor has been {@linkplain #isInitialized
|
||||
* initialized}.
|
||||
*
|
||||
* <p>Subclasses are free to override the implementation and
|
||||
* specification of any of the methods in this class as long as the
|
||||
* general {@link jdkx.annotation.processing.Processor Processor}
|
||||
* contract for that method is obeyed.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @since 1.6
|
||||
*/
|
||||
public abstract class AbstractProcessor implements Processor {
|
||||
/**
|
||||
* Processing environment providing by the tool framework.
|
||||
*/
|
||||
protected ProcessingEnvironment processingEnv;
|
||||
private boolean initialized = false;
|
||||
|
||||
/**
|
||||
* Constructor for subclasses to call.
|
||||
*/
|
||||
protected AbstractProcessor() {}
|
||||
|
||||
/**
|
||||
* If the processor class is annotated with {@link
|
||||
* SupportedOptions}, return an unmodifiable set with the same set
|
||||
* of strings as the annotation. If the class is not so
|
||||
* annotated, an empty set is returned.
|
||||
*
|
||||
* @return the options recognized by this processor, or an empty
|
||||
* set if none
|
||||
*/
|
||||
public Set<String> getSupportedOptions() {
|
||||
SupportedOptions so = this.getClass().getAnnotation(SupportedOptions.class);
|
||||
return (so == null) ?
|
||||
Collections.emptySet() :
|
||||
arrayToSet(so.value(), false, "option value", "@SupportedOptions");
|
||||
}
|
||||
|
||||
/**
|
||||
* If the processor class is annotated with {@link
|
||||
* SupportedAnnotationTypes}, return an unmodifiable set with the
|
||||
* same set of strings as the annotation. If the class is not so
|
||||
* annotated, an empty set is returned.
|
||||
*
|
||||
* If the {@linkplain ProcessingEnvironment#getSourceVersion source
|
||||
* version} does not support modules, in other words if it is less
|
||||
* than or equal to {@link SourceVersion#RELEASE_8 RELEASE_8},
|
||||
* then any leading {@linkplain Processor#getSupportedAnnotationTypes
|
||||
* module prefixes} are stripped from the names.
|
||||
*
|
||||
* @return the names of the annotation interfaces supported by
|
||||
* this processor, or an empty set if none
|
||||
*/
|
||||
public Set<String> getSupportedAnnotationTypes() {
|
||||
SupportedAnnotationTypes sat = this.getClass().getAnnotation(SupportedAnnotationTypes.class);
|
||||
boolean initialized = isInitialized();
|
||||
if (sat == null) {
|
||||
if (initialized)
|
||||
processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING,
|
||||
"No SupportedAnnotationTypes annotation " +
|
||||
"found on " + this.getClass().getName() +
|
||||
", returning an empty set.");
|
||||
return Collections.emptySet();
|
||||
} else {
|
||||
boolean stripModulePrefixes =
|
||||
initialized &&
|
||||
processingEnv.getSourceVersion().compareTo(SourceVersion.RELEASE_8) <= 0;
|
||||
return arrayToSet(sat.value(), stripModulePrefixes,
|
||||
"annotation type", "@SupportedAnnotationTypes");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the processor class is annotated with {@link
|
||||
* SupportedSourceVersion}, return the source version in the
|
||||
* annotation. If the class is not so annotated, {@link
|
||||
* SourceVersion#RELEASE_6} is returned.
|
||||
*
|
||||
* @return the latest source version supported by this processor
|
||||
*/
|
||||
public SourceVersion getSupportedSourceVersion() {
|
||||
SupportedSourceVersion ssv = this.getClass().getAnnotation(SupportedSourceVersion.class);
|
||||
SourceVersion sv = null;
|
||||
if (ssv == null) {
|
||||
sv = SourceVersion.RELEASE_6;
|
||||
if (isInitialized())
|
||||
processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING,
|
||||
"No SupportedSourceVersion annotation " +
|
||||
"found on " + this.getClass().getName() +
|
||||
", returning " + sv + ".");
|
||||
} else
|
||||
sv = ssv.value();
|
||||
return sv;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the processor with the processing environment by
|
||||
* setting the {@code processingEnv} field to the value of the
|
||||
* {@code processingEnv} argument. An {@code
|
||||
* IllegalStateException} will be thrown if this method is called
|
||||
* more than once on the same object.
|
||||
*
|
||||
* @param processingEnv environment to access facilities the tool framework
|
||||
* provides to the processor
|
||||
* @throws IllegalStateException if this method is called more than once.
|
||||
*/
|
||||
public synchronized void init(ProcessingEnvironment processingEnv) {
|
||||
if (initialized)
|
||||
throw new IllegalStateException("Cannot call init more than once.");
|
||||
Objects.requireNonNull(processingEnv, "Tool provided null ProcessingEnvironment");
|
||||
|
||||
this.processingEnv = processingEnv;
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public abstract boolean process(Set<? extends TypeElement> annotations,
|
||||
RoundEnvironment roundEnv);
|
||||
|
||||
/**
|
||||
* {@return an empty iterable of completions}
|
||||
*
|
||||
* @param element {@inheritDoc}
|
||||
* @param annotation {@inheritDoc}
|
||||
* @param member {@inheritDoc}
|
||||
* @param userText {@inheritDoc}
|
||||
*/
|
||||
public Iterable<? extends Completion> getCompletions(Element element,
|
||||
AnnotationMirror annotation,
|
||||
ExecutableElement member,
|
||||
String userText) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return {@code true} if this object has been {@linkplain #init
|
||||
* initialized}, {@code false} otherwise}
|
||||
*/
|
||||
protected synchronized boolean isInitialized() {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
private Set<String> arrayToSet(String[] array,
|
||||
boolean stripModulePrefixes,
|
||||
String contentType,
|
||||
String annotationName) {
|
||||
assert array != null;
|
||||
Set<String> set = new HashSet<>();
|
||||
for (String s : array) {
|
||||
boolean stripped = false;
|
||||
if (stripModulePrefixes) {
|
||||
int index = s.indexOf('/');
|
||||
if (index != -1) {
|
||||
s = s.substring(index + 1);
|
||||
stripped = true;
|
||||
}
|
||||
}
|
||||
boolean added = set.add(s);
|
||||
// Don't issue a duplicate warning when the module name is
|
||||
// stripped off to avoid spurious warnings in a case like
|
||||
// "foo/a.B", "bar/a.B".
|
||||
if (!added && !stripped && isInitialized() ) {
|
||||
processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING,
|
||||
"Duplicate " + contentType +
|
||||
" ``" + s + "'' for processor " +
|
||||
this.getClass().getName() +
|
||||
" in its " + annotationName +
|
||||
"annotation.");
|
||||
}
|
||||
}
|
||||
return Collections.unmodifiableSet(set);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.annotation.processing;
|
||||
|
||||
/**
|
||||
* A suggested {@linkplain Processor#getCompletions <em>completion</em>} for an
|
||||
* annotation. A completion is text meant to be inserted into a
|
||||
* program as part of an annotation.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @since 1.6
|
||||
*/
|
||||
public interface Completion {
|
||||
|
||||
/**
|
||||
* {@return the text of the suggested completion}
|
||||
*/
|
||||
String getValue();
|
||||
|
||||
/**
|
||||
* {@return an informative message about the completion}
|
||||
*/
|
||||
String getMessage();
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.annotation.processing;
|
||||
|
||||
/**
|
||||
* Utility class for assembling {@link Completion} objects.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @since 1.6
|
||||
*/
|
||||
public class Completions {
|
||||
// No instances for you.
|
||||
private Completions() {}
|
||||
|
||||
private static class SimpleCompletion implements Completion {
|
||||
private String value;
|
||||
private String message;
|
||||
|
||||
SimpleCompletion(String value, String message) {
|
||||
if (value == null || message == null)
|
||||
throw new NullPointerException("Null completion strings not accepted.");
|
||||
this.value = value;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[\"" + value + "\", \"" + message + "\"]";
|
||||
}
|
||||
// Default equals and hashCode are fine.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a completion of the value and message}
|
||||
*
|
||||
* @param value the text of the completion
|
||||
* @param message a message about the completion
|
||||
*/
|
||||
public static Completion of(String value, String message) {
|
||||
return new SimpleCompletion(value, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a completion of the value and an empty message}
|
||||
*
|
||||
* @param value the text of the completion
|
||||
*/
|
||||
public static Completion of(String value) {
|
||||
return new SimpleCompletion(value, "");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,411 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.annotation.processing;
|
||||
|
||||
import jdkx.tools.JavaFileManager;
|
||||
import jdkx.tools.*;
|
||||
import jdkx.lang.model.element.Element;
|
||||
import jdkx.lang.model.util.Elements;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This interface supports the creation of new files by an annotation
|
||||
* processor. Files created in this way will be known to the
|
||||
* annotation processing tool implementing this interface, better
|
||||
* enabling the tool to manage them. Source and class files so
|
||||
* created will be {@linkplain RoundEnvironment#getRootElements
|
||||
* considered for processing} by the tool in a subsequent {@linkplain
|
||||
* RoundEnvironment round of processing} after the {@code close}
|
||||
* method has been called on the {@code Writer} or {@code
|
||||
* OutputStream} used to write the contents of the file.
|
||||
*
|
||||
* Three kinds of files are distinguished: source files, class files,
|
||||
* and auxiliary resource files.
|
||||
*
|
||||
* <p> There are two distinguished supported locations (subtrees
|
||||
* within the logical file system) where newly created files are
|
||||
* placed: one for {@linkplain
|
||||
* jdkx.tools.StandardLocation#SOURCE_OUTPUT new source files}, and
|
||||
* one for {@linkplain jdkx.tools.StandardLocation#CLASS_OUTPUT new
|
||||
* class files}. (These might be specified on a tool's command line,
|
||||
* for example, using flags such as {@code -s} and {@code -d}.) The
|
||||
* actual locations for new source files and new class files may or
|
||||
* may not be distinct on a particular run of the tool. Resource
|
||||
* files may be created in either location. The methods for reading
|
||||
* and writing resources take a relative name argument. A relative
|
||||
* name is a non-null, non-empty sequence of path segments separated
|
||||
* by {@code '/'}; {@code '.'} and {@code '..'} are invalid path
|
||||
* segments. A valid relative name must match the
|
||||
* "path-rootless" rule of <a
|
||||
* href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>, section
|
||||
* 3.3.
|
||||
*
|
||||
* <p>The file creation methods take a variable number of arguments to
|
||||
* allow the <em>originating elements</em> to be provided as hints to
|
||||
* the tool infrastructure to better manage dependencies. The
|
||||
* originating elements are the classes or interfaces or packages
|
||||
* (representing {@code package-info} files) or modules (representing
|
||||
* {@code module-info} files) which caused an annotation processor to
|
||||
* attempt to create a new file. For example, if an annotation
|
||||
* processor tries to create a source file, {@code
|
||||
* GeneratedFromUserSource}, in response to processing
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* @Generate
|
||||
* public class UserSource {}
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* the type element for {@code UserSource} should be passed as part of
|
||||
* the creation method call as in:
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* filer.createSourceFile("GeneratedFromUserSource",
|
||||
* eltUtils.getTypeElement("UserSource"));
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* If there are no originating elements, none need to be passed. This
|
||||
* information may be used in an incremental environment to determine
|
||||
* the need to rerun processors or remove generated files.
|
||||
* Non-incremental environments may ignore the originating element
|
||||
* information.
|
||||
*
|
||||
* <p> During each run of an annotation processing tool, a file with a
|
||||
* given pathname may be created only once. If that file already
|
||||
* exists before the first attempt to create it, the old contents will
|
||||
* be deleted. Any subsequent attempt to create the same file during
|
||||
* a run will throw a {@link FilerException}, as will attempting to
|
||||
* create both a class file and source file for the same type name or
|
||||
* same package name. The {@linkplain Processor initial inputs} to
|
||||
* the tool are considered to be created by the zeroth round;
|
||||
* therefore, attempting to create a source or class file
|
||||
* corresponding to one of those inputs will result in a {@link
|
||||
* FilerException}.
|
||||
*
|
||||
* <p> In general, processors must not knowingly attempt to overwrite
|
||||
* existing files that were not generated by some processor. A {@code
|
||||
* Filer} may reject attempts to open a file corresponding to an
|
||||
* existing class or interface, like {@code java.lang.Object}. Likewise, the
|
||||
* invoker of the annotation processing tool must not knowingly
|
||||
* configure the tool such that the discovered processors will attempt
|
||||
* to overwrite existing files that were not generated.
|
||||
*
|
||||
* <p> Processors can indicate a source or class file is generated by
|
||||
* including a {@link jdkx.annotation.processing.Generated}
|
||||
* annotation if the environment is configured so that that class or
|
||||
* interface is accessible.
|
||||
*
|
||||
* @apiNote Some of the effect of overwriting a file can be
|
||||
* achieved by using a <i>decorator</i>-style pattern. Instead of
|
||||
* modifying a class directly, the class is designed so that either
|
||||
* its superclass is generated by annotation processing or subclasses
|
||||
* of the class are generated by annotation processing. If the
|
||||
* subclasses are generated, the parent class may be designed to use
|
||||
* factories instead of public constructors so that only subclass
|
||||
* instances would be presented to clients of the parent class.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @since 1.6
|
||||
*/
|
||||
public interface Filer {
|
||||
/**
|
||||
* Creates a new source file and returns an object to allow
|
||||
* writing to it. A source file for a class, interface, or a
|
||||
* package can be created.
|
||||
*
|
||||
* The file's name and path (relative to the {@linkplain
|
||||
* StandardLocation#SOURCE_OUTPUT root output location for source
|
||||
* files}) are based on the name of the item to be declared in
|
||||
* that file as well as the specified module for the item (if
|
||||
* any).
|
||||
*
|
||||
* If more than one class or interface is being declared in a single file (that
|
||||
* is, a single compilation unit), the name of the file should
|
||||
* correspond to the name of the principal top-level class or interface (the
|
||||
* public one, for example).
|
||||
*
|
||||
* <p>A source file can also be created to hold information about
|
||||
* a package, including package annotations. To create a source
|
||||
* file for a named package, have the {@code name} argument be the
|
||||
* package's name followed by {@code ".package-info"}; to create a
|
||||
* source file for an unnamed package, use {@code "package-info"}.
|
||||
*
|
||||
* <p>The optional module name is prefixed to the type name or
|
||||
* package name and separated using a "{@code /}" character. For
|
||||
* example, to create a source file for class {@code a.B} in module
|
||||
* {@code foo}, use a {@code name} argument of {@code "foo/a.B"}.
|
||||
*
|
||||
* <p>If no explicit module prefix is given and modules are supported
|
||||
* in the environment, a suitable module is inferred. If a suitable
|
||||
* module cannot be inferred {@link FilerException} is thrown.
|
||||
* An implementation may use information about the configuration of
|
||||
* the annotation processing tool as part of the inference.
|
||||
*
|
||||
* <p>Creating a source file in or for an <em>unnamed</em> package in a <em>named</em>
|
||||
* module is <em>not</em> supported.
|
||||
*
|
||||
* @apiNote To use a particular {@linkplain
|
||||
* java.nio.charset.Charset charset} to encode the contents of the
|
||||
* file, an {@code OutputStreamWriter} with the chosen charset can
|
||||
* be created from the {@code OutputStream} from the returned
|
||||
* object. If the {@code Writer} from the returned object is
|
||||
* directly used for writing, its charset is determined by the
|
||||
* implementation. An annotation processing tool may have an
|
||||
* {@code -encoding} flag or analogous option for specifying this;
|
||||
* otherwise, it will typically be the platform's default
|
||||
* encoding.
|
||||
*
|
||||
* <p>To avoid subsequent errors, the contents of the source file
|
||||
* should be compatible with the {@linkplain
|
||||
* ProcessingEnvironment#getSourceVersion source version} being used
|
||||
* for this run.
|
||||
*
|
||||
* @implNote In the reference implementation, if the annotation
|
||||
* processing tool is processing a single module <i>M</i>,
|
||||
* then <i>M</i> is used as the module for files created without
|
||||
* an explicit module prefix. If the tool is processing multiple
|
||||
* modules, and {@link
|
||||
* Elements#getPackageElement(java.lang.CharSequence)
|
||||
* Elements.getPackageElement(package-of(name))}
|
||||
* returns a package, the module that owns the returned package is used
|
||||
* as the target module. A separate option may be used to provide the target
|
||||
* module if it cannot be determined using the above rules.
|
||||
*
|
||||
* @param name canonical (fully qualified) name of the principal class or interface
|
||||
* being declared in this file or a package name followed by
|
||||
* {@code ".package-info"} for a package information file
|
||||
* @param originatingElements class, interface, package, or module
|
||||
* elements causally associated with the creation of this file,
|
||||
* may be elided or {@code null}
|
||||
* @return a {@code JavaFileObject} to write the new source file
|
||||
* @throws FilerException if the same pathname has already been
|
||||
* created, the same class or interface has already been created, the name is
|
||||
* otherwise not valid for the entity requested to being created,
|
||||
* if the target module cannot be determined, if the target
|
||||
* module is not writable, or a module is specified when the environment
|
||||
* doesn't support modules.
|
||||
* @throws IOException if the file cannot be created
|
||||
* @jls 7.3 Compilation Units
|
||||
*/
|
||||
JavaFileObject createSourceFile(CharSequence name,
|
||||
Element... originatingElements) throws IOException;
|
||||
|
||||
/**
|
||||
* Creates a new class file, and returns an object to allow
|
||||
* writing to it. A class file for a class, interface, or a package can
|
||||
* be created.
|
||||
*
|
||||
* The file's name and path (relative to the {@linkplain
|
||||
* StandardLocation#CLASS_OUTPUT root output location for class
|
||||
* files}) are based on the name of the item to be declared as
|
||||
* well as the specified module for the item (if any).
|
||||
*
|
||||
* <p>A class file can also be created to hold information about a
|
||||
* package, including package annotations. To create a class file
|
||||
* for a named package, have the {@code name} argument be the
|
||||
* package's name followed by {@code ".package-info"}; creating a
|
||||
* class file for an unnamed package is not supported.
|
||||
*
|
||||
* <p>The optional module name is prefixed to the type name or
|
||||
* package name and separated using a "{@code /}" character. For
|
||||
* example, to create a class file for class {@code a.B} in module
|
||||
* {@code foo}, use a {@code name} argument of {@code "foo/a.B"}.
|
||||
*
|
||||
* <p>If no explicit module prefix is given and modules are supported
|
||||
* in the environment, a suitable module is inferred. If a suitable
|
||||
* module cannot be inferred {@link FilerException} is thrown.
|
||||
* An implementation may use information about the configuration of
|
||||
* the annotation processing tool as part of the inference.
|
||||
*
|
||||
* <p>Creating a class file in or for an <em>unnamed</em> package in a <em>named</em>
|
||||
* module is <em>not</em> supported.
|
||||
*
|
||||
* @apiNote To avoid subsequent errors, the contents of the class
|
||||
* file should be compatible with the {@linkplain
|
||||
* ProcessingEnvironment#getSourceVersion source version} being
|
||||
* used for this run.
|
||||
*
|
||||
* @implNote In the reference implementation, if the annotation
|
||||
* processing tool is processing a single module <i>M</i>,
|
||||
* then <i>M</i> is used as the module for files created without
|
||||
* an explicit module prefix. If the tool is processing multiple
|
||||
* modules, and {@link
|
||||
* Elements#getPackageElement(java.lang.CharSequence)
|
||||
* Elements.getPackageElement(package-of(name))}
|
||||
* returns a package, the module that owns the returned package is used
|
||||
* as the target module. A separate option may be used to provide the target
|
||||
* module if it cannot be determined using the above rules.
|
||||
*
|
||||
* @param name binary name of the class or interface being written
|
||||
* or a package name followed by {@code ".package-info"} for a
|
||||
* package information file
|
||||
* @param originatingElements class or interface or package or
|
||||
* module elements causally associated with the creation of this
|
||||
* file, may be elided or {@code null}
|
||||
* @return a {@code JavaFileObject} to write the new class file
|
||||
* @throws FilerException if the same pathname has already been
|
||||
* created, the same class or interface has already been created, the name is
|
||||
* not valid for a class or interface, if the target module cannot be determined,
|
||||
* if the target module is not writable, or a module is specified when
|
||||
* the environment doesn't support modules.
|
||||
* @throws IOException if the file cannot be created
|
||||
*/
|
||||
JavaFileObject createClassFile(CharSequence name,
|
||||
Element... originatingElements) throws IOException;
|
||||
|
||||
/**
|
||||
* Creates a new auxiliary resource file for writing and returns a
|
||||
* file object for it. The file may be located along with the
|
||||
* newly created source files, newly created binary files, or
|
||||
* other supported location. The locations {@link
|
||||
* StandardLocation#CLASS_OUTPUT CLASS_OUTPUT} and {@link
|
||||
* StandardLocation#SOURCE_OUTPUT SOURCE_OUTPUT} must be
|
||||
* supported. The resource may be named relative to some module
|
||||
* and/or package (as are source and class files), and from there
|
||||
* by a relative pathname. In a loose sense, the full pathname of
|
||||
* the new file will be the concatenation of {@code location},
|
||||
* {@code moduleAndPkg}, and {@code relativeName}.
|
||||
*
|
||||
* If {@code moduleAndPkg} contains a "{@code /}" character, the
|
||||
* prefix before the "{@code /}" character is the module name and
|
||||
* the suffix after the "{@code /}" character is the package
|
||||
* name. The package suffix may be empty. If {@code moduleAndPkg}
|
||||
* does not contain a "{@code /}" character, the entire argument
|
||||
* is interpreted as a package name.
|
||||
*
|
||||
* <p>If the given location is neither a {@linkplain
|
||||
* JavaFileManager.Location#isModuleOrientedLocation()
|
||||
* module oriented location}, nor an {@linkplain
|
||||
* JavaFileManager.Location#isOutputLocation()
|
||||
* output location containing multiple modules}, and the explicit
|
||||
* module prefix is given, {@link FilerException} is thrown.
|
||||
*
|
||||
* <p>If the given location is either a module oriented location,
|
||||
* or an output location containing multiple modules, and no explicit
|
||||
* modules prefix is given, a suitable module is
|
||||
* inferred. If a suitable module cannot be inferred {@link
|
||||
* FilerException} is thrown. An implementation may use information
|
||||
* about the configuration of the annotation processing tool
|
||||
* as part of the inference.
|
||||
*
|
||||
* <p>Files created via this method are <em>not</em> registered for
|
||||
* annotation processing, even if the full pathname of the file
|
||||
* would correspond to the full pathname of a new source file
|
||||
* or new class file.
|
||||
*
|
||||
* @implNote In the reference implementation, if the annotation
|
||||
* processing tool is processing a single module <i>M</i>,
|
||||
* then <i>M</i> is used as the module for files created without
|
||||
* an explicit module prefix. If the tool is processing multiple
|
||||
* modules, and {@link
|
||||
* Elements#getPackageElement(java.lang.CharSequence)
|
||||
* Elements.getPackageElement(package-of(name))}
|
||||
* returns a package, the module that owns the returned package is used
|
||||
* as the target module. A separate option may be used to provide the target
|
||||
* module if it cannot be determined using the above rules.
|
||||
*
|
||||
* @param location location of the new file
|
||||
* @param moduleAndPkg module and/or package relative to which the file
|
||||
* should be named, or the empty string if none
|
||||
* @param relativeName final pathname components of the file
|
||||
* @param originatingElements class or interface or package or
|
||||
* module elements causally associated with the creation of this
|
||||
* file, may be elided or
|
||||
* {@code null}
|
||||
* @return a {@code FileObject} to write the new resource
|
||||
* @throws IOException if the file cannot be created
|
||||
* @throws FilerException if the same pathname has already been
|
||||
* created, if the target module cannot be determined,
|
||||
* or if the target module is not writable, or if an explicit
|
||||
* target module is specified and the location does not support it.
|
||||
* @throws IllegalArgumentException for an unsupported location
|
||||
* @throws IllegalArgumentException if {@code moduleAndPkg} is ill-formed
|
||||
* @throws IllegalArgumentException if {@code relativeName} is not relative
|
||||
*/
|
||||
FileObject createResource(JavaFileManager.Location location,
|
||||
CharSequence moduleAndPkg,
|
||||
CharSequence relativeName,
|
||||
Element... originatingElements) throws IOException;
|
||||
|
||||
/**
|
||||
* Returns an object for reading an existing resource. The
|
||||
* locations {@link StandardLocation#CLASS_OUTPUT CLASS_OUTPUT}
|
||||
* and {@link StandardLocation#SOURCE_OUTPUT SOURCE_OUTPUT} must
|
||||
* be supported.
|
||||
*
|
||||
* <p>If {@code moduleAndPkg} contains a "{@code /}" character, the
|
||||
* prefix before the "{@code /}" character is the module name and
|
||||
* the suffix after the "{@code /}" character is the package
|
||||
* name. The package suffix may be empty; however, if a module
|
||||
* name is present, it must be nonempty. If {@code moduleAndPkg}
|
||||
* does not contain a "{@code /}" character, the entire argument
|
||||
* is interpreted as a package name.
|
||||
*
|
||||
* <p>If the given location is neither a {@linkplain
|
||||
* JavaFileManager.Location#isModuleOrientedLocation()
|
||||
* module oriented location}, nor an {@linkplain
|
||||
* JavaFileManager.Location#isOutputLocation()
|
||||
* output location containing multiple modules}, and the explicit
|
||||
* module prefix is given, {@link FilerException} is thrown.
|
||||
*
|
||||
* <p>If the given location is either a module oriented location,
|
||||
* or an output location containing multiple modules, and no explicit
|
||||
* modules prefix is given, a suitable module is
|
||||
* inferred. If a suitable module cannot be inferred {@link
|
||||
* FilerException} is thrown. An implementation may use information
|
||||
* about the configuration of the annotation processing tool
|
||||
* as part of the inference.
|
||||
*
|
||||
* @implNote In the reference implementation, if the annotation
|
||||
* processing tool is processing a single module <i>M</i>,
|
||||
* then <i>M</i> is used as the module for files read without
|
||||
* an explicit module prefix. If the tool is processing multiple
|
||||
* modules, and {@link
|
||||
* Elements#getPackageElement(java.lang.CharSequence)
|
||||
* Elements.getPackageElement(package-of(name))}
|
||||
* returns a package, the module that owns the returned package is used
|
||||
* as the source module. A separate option may be used to provide the target
|
||||
* module if it cannot be determined using the above rules.
|
||||
*
|
||||
* @param location location of the file
|
||||
* @param moduleAndPkg module and/or package relative to which the file
|
||||
* should be searched for, or the empty string if none
|
||||
* @param relativeName final pathname components of the file
|
||||
* @return an object to read the file
|
||||
* @throws FilerException if the same pathname has already been
|
||||
* opened for writing, if the source module cannot be determined,
|
||||
* or if the target module is not writable, or if an explicit target
|
||||
* module is specified and the location does not support it.
|
||||
* @throws IOException if the file cannot be opened
|
||||
* @throws IllegalArgumentException for an unsupported location
|
||||
* @throws IllegalArgumentException if {@code moduleAndPkg} is ill-formed
|
||||
* @throws IllegalArgumentException if {@code relativeName} is not relative
|
||||
*/
|
||||
FileObject getResource(JavaFileManager.Location location,
|
||||
CharSequence moduleAndPkg,
|
||||
CharSequence relativeName) throws IOException;
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.annotation.processing;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Indicates a {@link Filer} detected an attempt to open a file that
|
||||
* would violate the guarantees provided by the {@code Filer}. Those
|
||||
* guarantees include not creating the same file more than once, not
|
||||
* creating multiple files corresponding to the same class or
|
||||
* interface or package, and not creating files for classes or
|
||||
* interfaces with invalid names.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @since 1.6
|
||||
*/
|
||||
public class FilerException extends IOException {
|
||||
static final long serialVersionUID = 8426423106453163293L;
|
||||
/**
|
||||
* Constructs an exception with the specified detail message.
|
||||
* @param s the detail message, which should include the name of
|
||||
* the file attempting to be opened; may be {@code null}
|
||||
*/
|
||||
public FilerException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdkx.annotation.processing;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.*;
|
||||
|
||||
/**
|
||||
* The Generated annotation is used to mark source code that has been generated.
|
||||
* It can also be used to differentiate user written code from generated code in
|
||||
* a single file.
|
||||
*
|
||||
* <h2>Examples:</h2>
|
||||
* <pre>
|
||||
* @Generated("com.example.Generator")
|
||||
* </pre>
|
||||
* <pre>
|
||||
* @Generated(value="com.example.Generator", date= "2017-07-04T12:08:56.235-0700")
|
||||
* </pre>
|
||||
* <pre>
|
||||
* @Generated(value="com.example.Generator", date= "2017-07-04T12:08:56.235-0700",
|
||||
* comments= "comment 1")
|
||||
* </pre>
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
@Documented
|
||||
@Retention(SOURCE)
|
||||
@Target({PACKAGE, TYPE, METHOD, CONSTRUCTOR, FIELD,
|
||||
LOCAL_VARIABLE, PARAMETER})
|
||||
public @interface Generated {
|
||||
|
||||
/**
|
||||
* The value element MUST have the name of the code generator. The
|
||||
* name is the fully qualified name of the code generator.
|
||||
*
|
||||
* @return The name of the code generator
|
||||
*/
|
||||
String[] value();
|
||||
|
||||
/**
|
||||
* Date when the source was generated. The date element must follow the ISO
|
||||
* 8601 standard. For example the date element would have the following
|
||||
* value 2017-07-04T12:08:56.235-0700 which represents 2017-07-04 12:08:56
|
||||
* local time in the U.S. Pacific Time time zone.
|
||||
*
|
||||
* @return The date the source was generated
|
||||
*/
|
||||
String date() default "";
|
||||
|
||||
/**
|
||||
* A place holder for any comments that the code generator may want to
|
||||
* include in the generated code.
|
||||
*
|
||||
* @return Comments that the code generated included
|
||||
*/
|
||||
String comments() default "";
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.annotation.processing;
|
||||
|
||||
import jdkx.tools.Diagnostic;
|
||||
import jdkx.lang.model.element.*;
|
||||
|
||||
/**
|
||||
* A {@code Messager} provides the way for an annotation processor to
|
||||
* report error messages, warnings, and other notices. Elements,
|
||||
* annotations, and annotation values can be passed to provide a
|
||||
* location hint for the message. However, such location hints may be
|
||||
* unavailable or only approximate.
|
||||
*
|
||||
* <p>Printing a message with an {@linkplain
|
||||
* jdkx.tools.Diagnostic.Kind#ERROR error kind} will {@linkplain
|
||||
* RoundEnvironment#errorRaised raise an error}.
|
||||
*
|
||||
* <p>Note that the messages "printed" by methods in this
|
||||
* interface may or may not appear as textual output to a location
|
||||
* like {@link System#out} or {@link System#err}. Implementations may
|
||||
* choose to present this information in a different fashion, such as
|
||||
* messages in a window.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @see ProcessingEnvironment#getLocale
|
||||
* @since 1.6
|
||||
*/
|
||||
public interface Messager {
|
||||
/**
|
||||
* Prints a message of the specified kind.
|
||||
*
|
||||
* @param kind the kind of message
|
||||
* @param msg the message, or an empty string if none
|
||||
*/
|
||||
void printMessage(Diagnostic.Kind kind, CharSequence msg);
|
||||
|
||||
/**
|
||||
* Prints a message of the specified kind at the location of the
|
||||
* element.
|
||||
*
|
||||
* @param kind the kind of message
|
||||
* @param msg the message, or an empty string if none
|
||||
* @param e the element to use as a position hint
|
||||
*/
|
||||
void printMessage(Diagnostic.Kind kind, CharSequence msg, Element e);
|
||||
|
||||
/**
|
||||
* Prints a message of the specified kind at the location of the
|
||||
* annotation mirror of the annotated element.
|
||||
*
|
||||
* @param kind the kind of message
|
||||
* @param msg the message, or an empty string if none
|
||||
* @param e the annotated element
|
||||
* @param a the annotation to use as a position hint
|
||||
*/
|
||||
void printMessage(Diagnostic.Kind kind, CharSequence msg, Element e, AnnotationMirror a);
|
||||
|
||||
/**
|
||||
* Prints a message of the specified kind at the location of the
|
||||
* annotation value inside the annotation mirror of the annotated
|
||||
* element.
|
||||
*
|
||||
* @param kind the kind of message
|
||||
* @param msg the message, or an empty string if none
|
||||
* @param e the annotated element
|
||||
* @param a the annotation containing the annotation value
|
||||
* @param v the annotation value to use as a position hint
|
||||
*/
|
||||
void printMessage(Diagnostic.Kind kind,
|
||||
CharSequence msg,
|
||||
Element e,
|
||||
AnnotationMirror a,
|
||||
AnnotationValue v);
|
||||
}
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.annotation.processing;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Locale;
|
||||
import jdkx.lang.model.SourceVersion;
|
||||
import jdkx.lang.model.util.Elements;
|
||||
import jdkx.lang.model.util.Types;
|
||||
|
||||
/**
|
||||
* An annotation processing tool framework will {@linkplain
|
||||
* Processor#init provide an annotation processor with an object
|
||||
* implementing this interface} so the processor can use facilities
|
||||
* provided by the framework to write new files, report error
|
||||
* messages, and find other utilities.
|
||||
*
|
||||
* <p>Third parties may wish to provide value-add wrappers around the
|
||||
* facility objects from this interface, for example a {@code Filer}
|
||||
* extension that allows multiple processors to coordinate writing out
|
||||
* a single source file. To enable this, for processors running in a
|
||||
* context where their side effects via the API could be visible to
|
||||
* each other, the tool infrastructure must provide corresponding
|
||||
* facility objects that are {@code .equals}, {@code Filer}s that are
|
||||
* {@code .equals}, and so on. In addition, the tool invocation must
|
||||
* be able to be configured such that from the perspective of the
|
||||
* running annotation processors, at least the chosen subset of helper
|
||||
* classes are viewed as being loaded by the same class loader.
|
||||
* (Since the facility objects manage shared state, the implementation
|
||||
* of a wrapper class must know whether or not the same base facility
|
||||
* object has been wrapped before.)
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @since 1.6
|
||||
*/
|
||||
public interface ProcessingEnvironment {
|
||||
/**
|
||||
* {@return the processor-specific options passed to the annotation
|
||||
* processing tool} Options are returned in the form of a map from
|
||||
* option name to option value. For an option with no value, the
|
||||
* corresponding value in the map is {@code null}.
|
||||
*
|
||||
* <p>See documentation of the particular tool infrastructure
|
||||
* being used for details on how to pass in processor-specific
|
||||
* options. For example, a command-line implementation may
|
||||
* distinguish processor-specific options by prefixing them with a
|
||||
* known string like {@code "-A"}; other tool implementations may
|
||||
* follow different conventions or provide alternative mechanisms.
|
||||
* A given implementation may also provide implementation-specific
|
||||
* ways of finding options passed to the tool in addition to the
|
||||
* processor-specific options.
|
||||
*/
|
||||
Map<String,String> getOptions();
|
||||
|
||||
/**
|
||||
* {@return the messager used to report errors, warnings, and other
|
||||
* notices}
|
||||
*/
|
||||
Messager getMessager();
|
||||
|
||||
/**
|
||||
* {@return the filer used to create new source, class, or auxiliary
|
||||
* files}
|
||||
*/
|
||||
Filer getFiler();
|
||||
|
||||
/**
|
||||
* {@return an implementation of some utility methods for
|
||||
* operating on elements}
|
||||
*/
|
||||
Elements getElementUtils();
|
||||
|
||||
/**
|
||||
* {@return an implementation of some utility methods for
|
||||
* operating on types}
|
||||
*/
|
||||
Types getTypeUtils();
|
||||
|
||||
/**
|
||||
* {@return the source version that any generated {@linkplain
|
||||
* Filer#createSourceFile source} and {@linkplain
|
||||
* Filer#createClassFile class} files should conform to}
|
||||
*
|
||||
* @see Processor#getSupportedSourceVersion
|
||||
*/
|
||||
SourceVersion getSourceVersion();
|
||||
|
||||
/**
|
||||
* {@return the current locale or {@code null} if no locale is in
|
||||
* effect} The locale can be be used to provide localized
|
||||
* {@linkplain Messager messages}.
|
||||
*/
|
||||
Locale getLocale();
|
||||
|
||||
/**
|
||||
* Returns {@code true} if <em>preview features</em> are enabled
|
||||
* and {@code false} otherwise.
|
||||
* @return whether or not preview features are enabled
|
||||
*
|
||||
* @implSpec The default implementation of this method returns
|
||||
* {@code false}.
|
||||
*
|
||||
* @since 13
|
||||
*/
|
||||
default boolean isPreviewEnabled() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,477 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.annotation.processing;
|
||||
|
||||
import java.util.Set;
|
||||
import jdkx.lang.model.util.Elements;
|
||||
import jdkx.lang.model.AnnotatedConstruct;
|
||||
import jdkx.lang.model.element.*;
|
||||
import jdkx.lang.model.SourceVersion;
|
||||
|
||||
/**
|
||||
* The interface for an annotation processor.
|
||||
*
|
||||
* <p>Annotation processing happens in a sequence of {@linkplain
|
||||
* jdkx.annotation.processing.RoundEnvironment rounds}. On each
|
||||
* round, a processor may be asked to {@linkplain #process process} a
|
||||
* subset of the annotations found on the source and class files
|
||||
* produced by a prior round. The inputs to the first round of
|
||||
* processing are the initial inputs to a run of the tool; these
|
||||
* initial inputs can be regarded as the output of a virtual zeroth
|
||||
* round of processing. If a processor was asked to process on a
|
||||
* given round, it will be asked to process on subsequent rounds,
|
||||
* including the last round, even if there are no annotations for it
|
||||
* to process. The tool infrastructure may also ask a processor to
|
||||
* process files generated implicitly by the tool's operation.
|
||||
*
|
||||
* <p> Each implementation of a {@code Processor} must provide a
|
||||
* public no-argument constructor to be used by tools to instantiate
|
||||
* the processor. The tool infrastructure will interact with classes
|
||||
* implementing this interface as follows:
|
||||
*
|
||||
* <ol>
|
||||
*
|
||||
* <li>If an existing {@code Processor} object is not being used, to
|
||||
* create an instance of a processor the tool calls the no-arg
|
||||
* constructor of the processor class.
|
||||
*
|
||||
* <li>Next, the tool calls the {@link #init init} method with
|
||||
* an appropriate {@link ProcessingEnvironment}.
|
||||
*
|
||||
* <li>Afterwards, the tool calls {@link #getSupportedAnnotationTypes
|
||||
* getSupportedAnnotationTypes}, {@link #getSupportedOptions
|
||||
* getSupportedOptions}, and {@link #getSupportedSourceVersion
|
||||
* getSupportedSourceVersion}. These methods are only called once per
|
||||
* run, not on each round.
|
||||
*
|
||||
* <li>As appropriate, the tool calls the {@link #process process}
|
||||
* method on the {@code Processor} object; a new {@code Processor}
|
||||
* object is <em>not</em> created for each round.
|
||||
*
|
||||
* </ol>
|
||||
*
|
||||
* If a processor object is created and used without the above
|
||||
* protocol being followed, then the processor's behavior is not
|
||||
* defined by this interface specification.
|
||||
*
|
||||
* <p> The tool uses a <i>discovery process</i> to find annotation
|
||||
* processors and decide whether or not they should be run. By
|
||||
* configuring the tool, the set of potential processors can be
|
||||
* controlled. For example, for a {@link jdkx.tools.JavaCompiler
|
||||
* JavaCompiler} the list of candidate processors to run can be
|
||||
* {@linkplain jdkx.tools.JavaCompiler.CompilationTask#setProcessors
|
||||
* set directly} or controlled by a {@linkplain
|
||||
* jdkx.tools.StandardLocation#ANNOTATION_PROCESSOR_PATH search path}
|
||||
* used for a {@linkplain java.util.ServiceLoader service-style}
|
||||
* lookup. Other tool implementations may have different
|
||||
* configuration mechanisms, such as command line options; for
|
||||
* details, refer to the particular tool's documentation. Which
|
||||
* processors the tool asks to {@linkplain #process run} is a function
|
||||
* of the interfaces of the annotations <em>{@linkplain
|
||||
* AnnotatedConstruct present}</em> on the {@linkplain
|
||||
* RoundEnvironment#getRootElements root elements}, what {@linkplain
|
||||
* #getSupportedAnnotationTypes annotation interfaces a processor
|
||||
* supports}, and whether or not a processor {@linkplain #process
|
||||
* claims the annotation interfaces it processes}. A processor will
|
||||
* be asked to process a subset of the annotation interfaces it
|
||||
* supports, possibly an empty set.
|
||||
*
|
||||
* For a given round, the tool computes the set of annotation
|
||||
* interfaces that are present on the elements enclosed within the
|
||||
* root elements. If there is at least one annotation interface
|
||||
* present, then as processors claim annotation interfaces, they are
|
||||
* removed from the set of unmatched annotation interfaces. When the
|
||||
* set is empty or no more processors are available, the round has run
|
||||
* to completion. If there are no annotation interfaces present,
|
||||
* annotation processing still occurs but only <i>universal
|
||||
* processors</i> which support processing all annotation interfaces,
|
||||
* {@code "*"}, can claim the (empty) set of annotation interfaces.
|
||||
*
|
||||
* <p>An annotation interface is considered present if there is at least
|
||||
* one annotation of that interface present on an element enclosed within
|
||||
* the root elements of a round. For this purpose, a type parameter is
|
||||
* considered to be enclosed by its {@linkplain
|
||||
* TypeParameterElement#getGenericElement generic
|
||||
* element}.
|
||||
|
||||
* For this purpose, a package element is <em>not</em> considered to
|
||||
* enclose the top-level classes and interfaces within that
|
||||
* package. (A root element representing a package is created when a
|
||||
* {@code package-info} file is processed.) Likewise, for this
|
||||
* purpose, a module element is <em>not</em> considered to enclose the
|
||||
* packages within that module. (A root element representing a module
|
||||
* is created when a {@code module-info} file is processed.)
|
||||
*
|
||||
* Annotations on {@linkplain
|
||||
* java.lang.annotation.ElementType#TYPE_USE type uses}, as opposed to
|
||||
* annotations on elements, are ignored when computing whether or not
|
||||
* an annotation interface is present.
|
||||
*
|
||||
* <p>An annotation is <em>present</em> if it meets the definition of being
|
||||
* present given in {@link AnnotatedConstruct}. In brief, an
|
||||
* annotation is considered present for the purposes of discovery if
|
||||
* it is directly present or present via inheritance. An annotation is
|
||||
* <em>not</em> considered present by virtue of being wrapped by a
|
||||
* container annotation. Operationally, this is equivalent to an
|
||||
* annotation being present on an element if and only if it would be
|
||||
* included in the results of {@link
|
||||
* Elements#getAllAnnotationMirrors(Element)} called on that element. Since
|
||||
* annotations inside container annotations are not considered
|
||||
* present, to properly process {@linkplain
|
||||
* java.lang.annotation.Repeatable repeatable annotation interfaces},
|
||||
* processors are advised to include both the repeatable annotation
|
||||
* interface and its containing annotation interface in the set of {@linkplain
|
||||
* #getSupportedAnnotationTypes() supported annotation interfaces} of a
|
||||
* processor.
|
||||
*
|
||||
* <p>Note that if a processor supports {@code "*"} and returns {@code
|
||||
* true}, all annotations are claimed. Therefore, a universal
|
||||
* processor being used to, for example, implement additional validity
|
||||
* checks should return {@code false} so as to not prevent other such
|
||||
* checkers from being able to run.
|
||||
*
|
||||
* <p>If a processor throws an uncaught exception, the tool may cease
|
||||
* other active annotation processors. If a processor raises an
|
||||
* error, the current round will run to completion and the subsequent
|
||||
* round will indicate an {@linkplain RoundEnvironment#errorRaised
|
||||
* error was raised}. Since annotation processors are run in a
|
||||
* cooperative environment, a processor should throw an uncaught
|
||||
* exception only in situations where no error recovery or reporting
|
||||
* is feasible.
|
||||
*
|
||||
* <p>The tool environment is not required to support annotation
|
||||
* processors that access environmental resources, either {@linkplain
|
||||
* RoundEnvironment per round} or {@linkplain ProcessingEnvironment
|
||||
* cross-round}, in a multi-threaded fashion.
|
||||
*
|
||||
* <p>If the methods that return configuration information about the
|
||||
* annotation processor return {@code null}, return other invalid
|
||||
* input, or throw an exception, the tool infrastructure must treat
|
||||
* this as an error condition.
|
||||
*
|
||||
* <p>To be robust when running in different tool implementations, an
|
||||
* annotation processor should have the following properties:
|
||||
*
|
||||
* <ol>
|
||||
*
|
||||
* <li>The result of processing a given input is not a function of the presence or absence
|
||||
* of other inputs (orthogonality).
|
||||
*
|
||||
* <li>Processing the same input produces the same output (consistency).
|
||||
*
|
||||
* <li>Processing input <i>A</i> followed by processing input <i>B</i>
|
||||
* is equivalent to processing <i>B</i> then <i>A</i>
|
||||
* (commutativity)
|
||||
*
|
||||
* <li>Processing an input does not rely on the presence of the output
|
||||
* of other annotation processors (independence)
|
||||
*
|
||||
* </ol>
|
||||
*
|
||||
* <p>The {@link Filer} interface discusses restrictions on how
|
||||
* processors can operate on files.
|
||||
*
|
||||
* @apiNote Implementors of this interface may find it convenient
|
||||
* to extend {@link AbstractProcessor} rather than implementing this
|
||||
* interface directly.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @since 1.6
|
||||
*/
|
||||
public interface Processor {
|
||||
/**
|
||||
* Returns the options recognized by this processor. An
|
||||
* implementation of the processing tool must provide a way to
|
||||
* pass processor-specific options distinctly from options passed
|
||||
* to the tool itself, see {@link ProcessingEnvironment#getOptions
|
||||
* getOptions}.
|
||||
*
|
||||
* <p>Each string returned in the set must be a period separated
|
||||
* sequence of {@linkplain
|
||||
* jdkx.lang.model.SourceVersion#isIdentifier identifiers}:
|
||||
*
|
||||
* <blockquote>
|
||||
* <dl>
|
||||
* <dt><i>SupportedOptionString:</i>
|
||||
* <dd><i>Identifiers</i>
|
||||
*
|
||||
* <dt><i>Identifiers:</i>
|
||||
* <dd> <i>Identifier</i>
|
||||
* <dd> <i>Identifier</i> {@code .} <i>Identifiers</i>
|
||||
*
|
||||
* <dt><i>Identifier:</i>
|
||||
* <dd>Syntactic identifier, including keywords and literals
|
||||
* </dl>
|
||||
* </blockquote>
|
||||
*
|
||||
* <p> A tool might use this information to determine if any
|
||||
* options provided by a user are unrecognized by any processor,
|
||||
* in which case it may wish to report a warning.
|
||||
*
|
||||
* @return the options recognized by this processor or an
|
||||
* empty set if none
|
||||
* @see jdkx.annotation.processing.SupportedOptions
|
||||
*/
|
||||
Set<String> getSupportedOptions();
|
||||
|
||||
/**
|
||||
* Returns the names of the annotation interfaces supported by this
|
||||
* processor. An element of the result may be the canonical
|
||||
* (fully qualified) name of a supported annotation interface.
|
||||
* Alternately it may be of the form "<code><i>name</i>.*</code>"
|
||||
* representing the set of all annotation interfaces with canonical
|
||||
* names beginning with "<code><i>name.</i></code>".
|
||||
*
|
||||
* In either of those cases, the name of the annotation interface can
|
||||
* be optionally preceded by a module name followed by a {@code
|
||||
* "/"} character. For example, if a processor supports {@code
|
||||
* "a.B"}, this can include multiple annotation interfaces named {@code
|
||||
* a.B} which reside in different modules. To only support {@code
|
||||
* a.B} in the {@code foo} module, instead use {@code "foo/a.B"}.
|
||||
*
|
||||
* If a module name is included, only an annotation in that module
|
||||
* is matched. In particular, if a module name is given in an
|
||||
* environment where modules are not supported, such as an
|
||||
* annotation processing environment configured for a {@linkplain
|
||||
* jdkx.annotation.processing.ProcessingEnvironment#getSourceVersion
|
||||
* source version} without modules, then the annotation interfaces with
|
||||
* a module name do <em>not</em> match.
|
||||
*
|
||||
* Finally, {@code "*"} by itself represents the set of all
|
||||
* annotation interfaces, including the empty set. Note that a
|
||||
* processor should not claim {@code "*"} unless it is actually
|
||||
* processing all files; claiming unnecessary annotations may
|
||||
* cause a performance slowdown in some environments.
|
||||
*
|
||||
* <p>Each string returned in the set must be accepted by the
|
||||
* following grammar:
|
||||
*
|
||||
* <blockquote>
|
||||
* <dl>
|
||||
* <dt><i>SupportedAnnotationTypeString:</i>
|
||||
* <dd><i>ModulePrefix</i><sub><i>opt</i></sub> <i>TypeName</i> <i>DotStar</i><sub><i>opt</i></sub>
|
||||
* <dd><code>*</code>
|
||||
*
|
||||
* <dt><i>ModulePrefix:</i>
|
||||
* <dd><i>ModuleName</i> <code>/</code>
|
||||
*
|
||||
* <dt><i>DotStar:</i>
|
||||
* <dd><code>.</code> <code>*</code>
|
||||
* </dl>
|
||||
* </blockquote>
|
||||
*
|
||||
* where <i>TypeName</i> and <i>ModuleName</i> are as defined in
|
||||
* <cite>The Java Language Specification</cite>
|
||||
* ({@jls 6.5 Determining the Meaning of a Name}).
|
||||
*
|
||||
* @apiNote When running in an environment which supports modules,
|
||||
* processors are encouraged to include the module prefix when
|
||||
* describing their supported annotation interfaces. The method {@link
|
||||
* AbstractProcessor#getSupportedAnnotationTypes
|
||||
* AbstractProcessor.getSupportedAnnotationTypes} provides support
|
||||
* for stripping off the module prefix when running in an
|
||||
* environment without modules.
|
||||
*
|
||||
* @return the names of the annotation interfaces supported by this processor
|
||||
* or an empty set if none
|
||||
* @see jdkx.annotation.processing.SupportedAnnotationTypes
|
||||
* @jls 3.8 Identifiers
|
||||
*/
|
||||
Set<String> getSupportedAnnotationTypes();
|
||||
|
||||
/**
|
||||
* {@return the latest source version supported by this annotation
|
||||
* processor}
|
||||
*
|
||||
* @see jdkx.annotation.processing.SupportedSourceVersion
|
||||
* @see ProcessingEnvironment#getSourceVersion
|
||||
*/
|
||||
SourceVersion getSupportedSourceVersion();
|
||||
|
||||
/**
|
||||
* Initializes the processor with the processing environment.
|
||||
*
|
||||
* @param processingEnv environment for facilities the tool framework
|
||||
* provides to the processor
|
||||
*/
|
||||
void init(ProcessingEnvironment processingEnv);
|
||||
|
||||
/**
|
||||
* Processes a set of annotation interfaces on type elements
|
||||
* originating from the prior round and returns whether or not
|
||||
* these annotation interfaces are claimed by this processor. If {@code
|
||||
* true} is returned, the annotation interfaces are claimed and subsequent
|
||||
* processors will not be asked to process them; if {@code false}
|
||||
* is returned, the annotation interfaces are unclaimed and subsequent
|
||||
* processors may be asked to process them. A processor may
|
||||
* always return the same boolean value or may vary the result
|
||||
* based on its own chosen criteria.
|
||||
*
|
||||
* <p>The input set will be empty if the processor supports {@code
|
||||
* "*"} and the root elements have no annotations. A {@code
|
||||
* Processor} must gracefully handle an empty set of annotations.
|
||||
*
|
||||
* @param annotations the annotation interfaces requested to be processed
|
||||
* @param roundEnv environment for information about the current and prior round
|
||||
* @return whether or not the set of annotation interfaces are claimed by this processor
|
||||
*/
|
||||
boolean process(Set<? extends TypeElement> annotations,
|
||||
RoundEnvironment roundEnv);
|
||||
|
||||
/**
|
||||
* Returns to the tool infrastructure an iterable of suggested
|
||||
* completions to an annotation. Since completions are being asked
|
||||
* for, the information provided about the annotation may be
|
||||
* incomplete, as if for a source code fragment. A processor may
|
||||
* return an empty iterable. Annotation processors should focus
|
||||
* their efforts on providing completions for annotation members
|
||||
* with additional validity constraints known to the processor, for
|
||||
* example an {@code int} member whose value should lie between 1
|
||||
* and 10 or a string member that should be recognized by a known
|
||||
* grammar, such as a regular expression or a URL.
|
||||
*
|
||||
* <p>Since incomplete programs are being modeled, some of the
|
||||
* parameters may only have partial information or may be {@code
|
||||
* null}. At least one of {@code element} and {@code userText}
|
||||
* must be non-{@code null}. If {@code element} is non-{@code null},
|
||||
* {@code annotation} and {@code member} may be {@code
|
||||
* null}. Processors may not throw a {@code NullPointerException}
|
||||
* if some parameters are {@code null}; if a processor has no
|
||||
* completions to offer based on the provided information, an
|
||||
* empty iterable can be returned. The processor may also return
|
||||
* a single completion with an empty value string and a message
|
||||
* describing why there are no completions.
|
||||
*
|
||||
* <p>Completions are informative and may reflect additional
|
||||
* validity checks performed by annotation processors. For
|
||||
* example, consider the simple annotation:
|
||||
*
|
||||
* <blockquote>
|
||||
* <pre>
|
||||
* @MersennePrime {
|
||||
* int value();
|
||||
* }
|
||||
* </pre>
|
||||
* </blockquote>
|
||||
*
|
||||
* (A Mersenne prime is prime number of the form
|
||||
* 2<sup><i>n</i></sup> - 1.) Given an {@code AnnotationMirror}
|
||||
* for this annotation interface, a list of all such primes in the
|
||||
* {@code int} range could be returned without examining any other
|
||||
* arguments to {@code getCompletions}:
|
||||
*
|
||||
* <blockquote>
|
||||
* <pre>
|
||||
* import static jdkx.annotation.processing.Completions.*;
|
||||
* ...
|
||||
* return List.of({@link Completions#of(String) of}("3"),
|
||||
* of("7"),
|
||||
* of("31"),
|
||||
* of("127"),
|
||||
* of("8191"),
|
||||
* of("131071"),
|
||||
* of("524287"),
|
||||
* of("2147483647"));
|
||||
* </pre>
|
||||
* </blockquote>
|
||||
*
|
||||
* A more informative set of completions would include the number
|
||||
* of each prime:
|
||||
*
|
||||
* <blockquote>
|
||||
* <pre>
|
||||
* return List.of({@link Completions#of(String, String) of}("3", "M2"),
|
||||
* of("7", "M3"),
|
||||
* of("31", "M5"),
|
||||
* of("127", "M7"),
|
||||
* of("8191", "M13"),
|
||||
* of("131071", "M17"),
|
||||
* of("524287", "M19"),
|
||||
* of("2147483647", "M31"));
|
||||
* </pre>
|
||||
* </blockquote>
|
||||
*
|
||||
* However, if the {@code userText} is available, it can be checked
|
||||
* to see if only a subset of the Mersenne primes are valid. For
|
||||
* example, if the user has typed
|
||||
*
|
||||
* <blockquote>
|
||||
* <code>
|
||||
* @MersennePrime(1
|
||||
* </code>
|
||||
* </blockquote>
|
||||
*
|
||||
* the value of {@code userText} will be {@code "1"}; and only
|
||||
* two of the primes are possible completions:
|
||||
*
|
||||
* <blockquote>
|
||||
* <pre>
|
||||
* return Arrays.asList(of("127", "M7"),
|
||||
* of("131071", "M17"));
|
||||
* </pre>
|
||||
* </blockquote>
|
||||
*
|
||||
* Sometimes no valid completion is possible. For example, there
|
||||
* is no in-range Mersenne prime starting with 9:
|
||||
*
|
||||
* <blockquote>
|
||||
* <code>
|
||||
* @MersennePrime(9
|
||||
* </code>
|
||||
* </blockquote>
|
||||
*
|
||||
* An appropriate response in this case is to either return an
|
||||
* empty list of completions,
|
||||
*
|
||||
* <blockquote>
|
||||
* <pre>
|
||||
* return Collections.emptyList();
|
||||
* </pre>
|
||||
* </blockquote>
|
||||
*
|
||||
* or a single empty completion with a helpful message
|
||||
*
|
||||
* <blockquote>
|
||||
* <pre>
|
||||
* return Arrays.asList(of("", "No in-range Mersenne primes start with 9"));
|
||||
* </pre>
|
||||
* </blockquote>
|
||||
*
|
||||
* @param element the element being annotated
|
||||
* @param annotation the (perhaps partial) annotation being
|
||||
* applied to the element
|
||||
* @param member the annotation member to return possible completions for
|
||||
* @param userText source code text to be completed
|
||||
*
|
||||
* @return suggested completions to the annotation
|
||||
*/
|
||||
Iterable<? extends Completion> getCompletions(Element element,
|
||||
AnnotationMirror annotation,
|
||||
ExecutableElement member,
|
||||
String userText);
|
||||
}
|
||||
+209
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.annotation.processing;
|
||||
|
||||
import jdkx.lang.model.element.Element;
|
||||
import jdkx.lang.model.element.TypeElement;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
/**
|
||||
* An annotation processing tool framework will {@linkplain
|
||||
* Processor#process provide an annotation processor with an object
|
||||
* implementing this interface} so that the processor can query for
|
||||
* information about a round of annotation processing.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @since 1.6
|
||||
*/
|
||||
public interface RoundEnvironment {
|
||||
/**
|
||||
* {@return {@code true} if types generated by this round will not
|
||||
* be subject to a subsequent round of annotation processing;
|
||||
* returns {@code false} otherwise}
|
||||
*/
|
||||
boolean processingOver();
|
||||
|
||||
/**
|
||||
* {@return {@code true} if an error was raised in the prior round
|
||||
* of processing; returns {@code false} otherwise}
|
||||
*/
|
||||
boolean errorRaised();
|
||||
|
||||
/**
|
||||
* Returns the {@linkplain Processor root elements} for annotation processing generated
|
||||
* by the prior round.
|
||||
*
|
||||
* @return the root elements for annotation processing generated
|
||||
* by the prior round, or an empty set if there were none
|
||||
*/
|
||||
Set<? extends Element> getRootElements();
|
||||
|
||||
/**
|
||||
* Returns the elements annotated with the given annotation type.
|
||||
* The annotation may appear directly or be inherited. Only
|
||||
* package elements, module elements, and type elements <i>included</i> in this
|
||||
* round of annotation processing, or declarations of members,
|
||||
* constructors, parameters, type parameters, or record components
|
||||
* declared within those, are returned. Included type elements are {@linkplain
|
||||
* #getRootElements root types} and any member types nested within
|
||||
* them. Elements of a package are not considered included simply
|
||||
* because a {@code package-info} file for that package was
|
||||
* created.
|
||||
* Likewise, elements of a module are not considered included
|
||||
* simply because a {@code module-info} file for that module was
|
||||
* created.
|
||||
*
|
||||
* @param a annotation type being requested
|
||||
* @return the elements annotated with the given annotation type,
|
||||
* or an empty set if there are none
|
||||
* @throws IllegalArgumentException if the argument does not
|
||||
* represent an annotation type
|
||||
*/
|
||||
Set<? extends Element> getElementsAnnotatedWith(TypeElement a);
|
||||
|
||||
/**
|
||||
* Returns the elements annotated with one or more of the given
|
||||
* annotation types.
|
||||
*
|
||||
* @apiNote This method may be useful when processing repeating
|
||||
* annotations by looking for an annotation type and its
|
||||
* containing annotation type at the same time.
|
||||
*
|
||||
* @implSpec The default implementation of this method creates an
|
||||
* empty result set, iterates over the annotations in the argument
|
||||
* array calling {@link #getElementsAnnotatedWith(TypeElement)} on
|
||||
* each annotation and adding those results to the result
|
||||
* set. Finally, the contents of the result set are returned as an
|
||||
* unmodifiable set.
|
||||
*
|
||||
* @param annotations annotation types being requested
|
||||
* @return the elements annotated with one or more of the given
|
||||
* annotation types, or an empty set if there are none
|
||||
* @throws IllegalArgumentException if the any elements of the
|
||||
* argument set do not represent an annotation type
|
||||
* @jls 9.6.3 Repeatable Annotation Interfaces
|
||||
* @since 9
|
||||
*/
|
||||
default Set<? extends Element> getElementsAnnotatedWithAny(TypeElement... annotations){
|
||||
// Use LinkedHashSet rather than HashSet for predictability
|
||||
Set<Element> result = new LinkedHashSet<>();
|
||||
for (TypeElement annotation : annotations) {
|
||||
result.addAll(getElementsAnnotatedWith(annotation));
|
||||
}
|
||||
return Collections.unmodifiableSet(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the elements annotated with the given annotation type.
|
||||
* The annotation may appear directly or be inherited. Only
|
||||
* package elements, module elements, and type elements <i>included</i> in this
|
||||
* round of annotation processing, or declarations of members,
|
||||
* constructors, parameters, type parameters, or record components
|
||||
* declared within those, are returned. Included type elements are {@linkplain
|
||||
* #getRootElements root types} and any member types nested within
|
||||
* them. Elements in a package are not considered included simply
|
||||
* because a {@code package-info} file for that package was
|
||||
* created.
|
||||
* Likewise, elements of a module are not considered included
|
||||
* simply because a {@code module-info} file for that module was
|
||||
* created.
|
||||
*
|
||||
* <p> Note: An implementation of this method typically performs
|
||||
* an internal conversion from the runtime reflective
|
||||
* representation of an annotation type as a {@code Class} object
|
||||
* to a different representation used for annotation
|
||||
* processing. The set of annotation types present in the runtime
|
||||
* context may differ from the set of annotation types present in
|
||||
* the context of annotation processing in a particular
|
||||
* environmental configuration. If an runtime annotation type is
|
||||
* not present in the annotation processing context, the situation
|
||||
* is not treated as an error and no elements are found for that
|
||||
* annotation type.
|
||||
*
|
||||
* @param a annotation type being requested
|
||||
* @return the elements annotated with the given annotation type,
|
||||
* or an empty set if there are none
|
||||
* @throws IllegalArgumentException if the argument does not
|
||||
* represent an annotation type
|
||||
*
|
||||
* @see jdkx.lang.model.AnnotatedConstruct#getAnnotation(Class)
|
||||
* @see jdkx.lang.model.AnnotatedConstruct#getAnnotationsByType(Class)
|
||||
*/
|
||||
Set<? extends Element> getElementsAnnotatedWith(Class<? extends Annotation> a);
|
||||
|
||||
/**
|
||||
* Returns the elements annotated with one or more of the given
|
||||
* annotation types.
|
||||
*
|
||||
* <p> Note: An implementation of this method typically performs
|
||||
* an internal conversion from the runtime reflective
|
||||
* representation of an annotation type as a {@code Class} object
|
||||
* to a different representation used for annotation
|
||||
* processing. The set of annotation types present in the runtime
|
||||
* context may differ from the set of annotation types present in
|
||||
* the context of annotation processing in a particular
|
||||
* environmental configuration. If an runtime annotation type is
|
||||
* not present in the annotation processing context, the situation
|
||||
* is not treated as an error and no elements are found for that
|
||||
* annotation type.
|
||||
*
|
||||
* @apiNote This method may be useful when processing repeating
|
||||
* annotations by looking for an annotation type and its
|
||||
* containing annotation type at the same time.
|
||||
*
|
||||
* @implSpec The default implementation of this method creates an
|
||||
* empty result set, iterates over the annotations in the argument
|
||||
* set calling {@link #getElementsAnnotatedWith(Class)} on
|
||||
* each annotation and adding those results to the result
|
||||
* set. Finally, the contents of the result set are returned as an
|
||||
* unmodifiable set.
|
||||
*
|
||||
* @param annotations annotation types being requested
|
||||
* @return the elements annotated with one or more of the given
|
||||
* annotation types, or an empty set if there are none
|
||||
* @throws IllegalArgumentException if the any elements of the
|
||||
* argument set do not represent an annotation type
|
||||
* @jls 9.6.3 Repeatable Annotation Interfaces
|
||||
*
|
||||
* @see jdkx.lang.model.AnnotatedConstruct#getAnnotation(Class)
|
||||
* @see jdkx.lang.model.AnnotatedConstruct#getAnnotationsByType(Class)
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
default Set<? extends Element> getElementsAnnotatedWithAny(Set<Class<? extends Annotation>> annotations){
|
||||
// Use LinkedHashSet rather than HashSet for predictability
|
||||
Set<Element> result = new LinkedHashSet<>();
|
||||
for (Class<? extends Annotation> annotation : annotations) {
|
||||
result.addAll(getElementsAnnotatedWith(annotation));
|
||||
}
|
||||
return Collections.unmodifiableSet(result);
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.annotation.processing;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import static java.lang.annotation.RetentionPolicy.*;
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
|
||||
/**
|
||||
* An annotation used to indicate what annotation interfaces an
|
||||
* annotation processor supports. The {@link
|
||||
* Processor#getSupportedAnnotationTypes} method can construct its
|
||||
* result from the value of this annotation, as done by {@link
|
||||
* AbstractProcessor#getSupportedAnnotationTypes}. Only {@linkplain
|
||||
* Processor#getSupportedAnnotationTypes strings conforming to the
|
||||
* grammar} should be used as values.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @since 1.6
|
||||
*/
|
||||
@Documented
|
||||
@Target(TYPE)
|
||||
@Retention(RUNTIME)
|
||||
public @interface SupportedAnnotationTypes {
|
||||
/**
|
||||
* {@return the names of the supported annotation interfaces}
|
||||
*/
|
||||
String [] value();
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.annotation.processing;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import static java.lang.annotation.RetentionPolicy.*;
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
|
||||
/**
|
||||
* An annotation used to indicate what options an annotation processor
|
||||
* supports. The {@link Processor#getSupportedOptions} method can
|
||||
* construct its result from the value of this annotation, as done by
|
||||
* {@link AbstractProcessor#getSupportedOptions}. Only {@linkplain
|
||||
* Processor#getSupportedOptions strings conforming to the
|
||||
* grammar} should be used as values.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @since 1.6
|
||||
*/
|
||||
@Documented
|
||||
@Target(TYPE)
|
||||
@Retention(RUNTIME)
|
||||
public @interface SupportedOptions {
|
||||
/**
|
||||
* {@return the supported options}
|
||||
*/
|
||||
String [] value();
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.annotation.processing;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import static java.lang.annotation.RetentionPolicy.*;
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import jdkx.lang.model.SourceVersion;
|
||||
|
||||
|
||||
/**
|
||||
* An annotation used to indicate the latest source version an
|
||||
* annotation processor supports. The {@link
|
||||
* Processor#getSupportedSourceVersion} method can construct its
|
||||
* result from the value of this annotation, as done by {@link
|
||||
* AbstractProcessor#getSupportedSourceVersion}.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @since 1.6
|
||||
*/
|
||||
@Documented
|
||||
@Target(TYPE)
|
||||
@Retention(RUNTIME)
|
||||
public @interface SupportedSourceVersion {
|
||||
/**
|
||||
* {@return the latest supported source version}
|
||||
*/
|
||||
SourceVersion value();
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Facilities for declaring annotation processors and for
|
||||
* allowing annotation processors to communicate with an annotation processing
|
||||
* tool environment.
|
||||
*
|
||||
* <p> Unless otherwise specified in a particular implementation, the
|
||||
* collections returned by methods in this package should be expected
|
||||
* to be unmodifiable by the caller and unsafe for concurrent access.
|
||||
*
|
||||
* <p> Unless otherwise specified, methods in this package will throw
|
||||
* a {@code NullPointerException} if given a {@code null} argument.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @since 1.6
|
||||
*/
|
||||
package jdkx.annotation.processing;
|
||||
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.util.List;
|
||||
import jdkx.lang.model.element.*;
|
||||
import jdkx.lang.model.type.*;
|
||||
|
||||
/**
|
||||
* Represents a construct that can be annotated.
|
||||
*
|
||||
* A construct is either an {@linkplain
|
||||
* jdkx.lang.model.element.Element element} or a {@linkplain
|
||||
* jdkx.lang.model.type.TypeMirror type}. Annotations on an element
|
||||
* are on a <em>declaration</em>, whereas annotations on a type are on
|
||||
* a specific <em>use</em> of a type name.
|
||||
*
|
||||
* As defined by <cite>The Java Language Specification</cite>
|
||||
* section {@jls 9.7.4}, an annotation on an element is a
|
||||
* <em>declaration annotation</em> and an annotation on a type is a
|
||||
* <em>type annotation</em>.
|
||||
*
|
||||
* The terms <em>directly present</em>, <em>present</em>,
|
||||
* <em>indirectly present</em>, and <em>associated </em> are used
|
||||
* throughout this interface to describe precisely which annotations,
|
||||
* either declaration annotations or type annotations, are returned by
|
||||
* the methods in this interface.
|
||||
*
|
||||
* <p>In the definitions below, an annotation <i>A</i> has an
|
||||
* annotation type <i>AT</i>. If <i>AT</i> is a repeatable annotation
|
||||
* type, the type of the containing annotation is <i>ATC</i>.
|
||||
*
|
||||
* <p>Annotation <i>A</i> is <em>directly present</em> on a construct
|
||||
* <i>C</i> if either:
|
||||
*
|
||||
* <ul>
|
||||
*
|
||||
* <li><i>A</i> is {@linkplain
|
||||
* jdkx.lang.model.util.Elements#getOrigin(AnnotatedConstruct,
|
||||
* AnnotationMirror) explicitly or implicitly}
|
||||
* declared as applying to
|
||||
* the source code representation of <i>C</i>.
|
||||
*
|
||||
* <p>Typically, if exactly one annotation of type <i>AT</i> appears in
|
||||
* the source code of representation of <i>C</i>, then <i>A</i> is
|
||||
* explicitly declared as applying to <i>C</i>.
|
||||
*
|
||||
* An annotation of type <i>AT</i> on a {@linkplain
|
||||
* RecordComponentElement record component} can be implicitly propagated
|
||||
* down to affiliated mandated members. Type annotations modifying the
|
||||
* type of a record component can be also propagated to mandated
|
||||
* members. Propagation of the annotations to mandated members is
|
||||
* governed by rules given in the <cite>The Java Language
|
||||
* Specification</cite>.
|
||||
*
|
||||
* If there are multiple annotations of type <i>AT</i> present on
|
||||
* <i>C</i>, then if <i>AT</i> is repeatable annotation type, an
|
||||
* annotation of type <i>ATC</i> is {@linkplain jdkx.lang.model.util.Elements#getOrigin(AnnotatedConstruct, AnnotationMirror) implicitly declared} on <i>C</i>.
|
||||
* <li> A representation of <i>A</i> appears in the executable output
|
||||
* for <i>C</i>, such as the {@code RuntimeVisibleAnnotations} (JVMS {@jvms 4.7.16}) or
|
||||
* {@code RuntimeVisibleParameterAnnotations} (JVMS {@jvms 4.7.17}) attributes of a class
|
||||
* file.
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* <p>An annotation <i>A</i> is <em>present</em> on a
|
||||
* construct <i>C</i> if either:
|
||||
* <ul>
|
||||
*
|
||||
* <li><i>A</i> is directly present on <i>C</i>.
|
||||
*
|
||||
* <li>No annotation of type <i>AT</i> is directly present on
|
||||
* <i>C</i>, and <i>C</i> is a class and <i>AT</i> is inheritable
|
||||
* and <i>A</i> is present on the superclass of <i>C</i>.
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* An annotation <i>A</i> is <em>indirectly present</em> on a construct
|
||||
* <i>C</i> if both:
|
||||
*
|
||||
* <ul>
|
||||
*
|
||||
* <li><i>AT</i> is a repeatable annotation type with a containing
|
||||
* annotation type <i>ATC</i>.
|
||||
*
|
||||
* <li>An annotation of type <i>ATC</i> is directly present on
|
||||
* <i>C</i> and <i>A</i> is an annotation included in the result of
|
||||
* calling the {@code value} method of the directly present annotation
|
||||
* of type <i>ATC</i>.
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* An annotation <i>A</i> is <em>associated</em> with a construct
|
||||
* <i>C</i> if either:
|
||||
*
|
||||
* <ul>
|
||||
*
|
||||
* <li> <i>A</i> is directly or indirectly present on <i>C</i>.
|
||||
*
|
||||
* <li> No annotation of type <i>AT</i> is directly or indirectly
|
||||
* present on <i>C</i>, and <i>C</i> is a class, and <i>AT</i> is
|
||||
* inheritable, and <i>A</i> is associated with the superclass of
|
||||
* <i>C</i>.
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* @since 1.8
|
||||
* @jls 9.6 Annotation Interfaces
|
||||
* @jls 9.6.4.3 {@code @Inherited}
|
||||
* @jls 9.7.4 Where Annotations May Appear
|
||||
* @jls 9.7.5 Multiple Annotations of the Same Interface
|
||||
*/
|
||||
public interface AnnotatedConstruct {
|
||||
/**
|
||||
* Returns the annotations that are <em>directly present</em> on
|
||||
* this construct.
|
||||
*
|
||||
* @return the annotations <em>directly present</em> on this
|
||||
* construct; an empty list if there are none
|
||||
*/
|
||||
List<? extends AnnotationMirror> getAnnotationMirrors();
|
||||
|
||||
/**
|
||||
* {@return this construct's annotation of the specified type if
|
||||
* such an annotation is <em>present</em>, else {@code null}}
|
||||
*
|
||||
* <p> The annotation returned by this method could contain an element
|
||||
* whose value is of type {@code Class}.
|
||||
* This value cannot be returned directly: information necessary to
|
||||
* locate and load a class (such as the class loader to use) is
|
||||
* not available, and the class might not be loadable at all.
|
||||
* Attempting to read a {@code Class} object by invoking the relevant
|
||||
* method on the returned annotation
|
||||
* will result in a {@link MirroredTypeException},
|
||||
* from which the corresponding {@link TypeMirror} may be extracted.
|
||||
* Similarly, attempting to read a {@code Class[]}-valued element
|
||||
* will result in a {@link MirroredTypesException}.
|
||||
*
|
||||
* <blockquote>
|
||||
* <i>Note:</i> This method is unlike others in this and related
|
||||
* interfaces. It operates on runtime reflective information —
|
||||
* representations of annotation types currently loaded into the
|
||||
* VM — rather than on the representations defined by and used
|
||||
* throughout these interfaces. Consequently, calling methods on
|
||||
* the returned annotation object can throw many of the exceptions
|
||||
* that can be thrown when calling methods on an annotation object
|
||||
* returned by core reflection. This method is intended for
|
||||
* callers that are written to operate on a known, fixed set of
|
||||
* annotation types.
|
||||
* </blockquote>
|
||||
*
|
||||
* @param <A> the annotation type
|
||||
* @param annotationType the {@code Class} object corresponding to
|
||||
* the annotation type
|
||||
*
|
||||
* @see #getAnnotationMirrors()
|
||||
* @see java.lang.reflect.AnnotatedElement#getAnnotation
|
||||
* @see EnumConstantNotPresentException
|
||||
* @see AnnotationTypeMismatchException
|
||||
* @see IncompleteAnnotationException
|
||||
* @see MirroredTypeException
|
||||
* @see MirroredTypesException
|
||||
* @jls 9.6.1 Annotation Interface Elements
|
||||
*/
|
||||
<A extends Annotation> A getAnnotation(Class<A> annotationType);
|
||||
|
||||
/**
|
||||
* Returns annotations that are <em>associated</em> with this construct.
|
||||
*
|
||||
* If there are no annotations associated with this construct, the
|
||||
* return value is an array of length 0.
|
||||
*
|
||||
* The order of annotations which are directly or indirectly
|
||||
* present on a construct <i>C</i> is computed as if indirectly present
|
||||
* annotations on <i>C</i> are directly present on <i>C</i> in place of their
|
||||
* container annotation, in the order in which they appear in the
|
||||
* value element of the container annotation.
|
||||
*
|
||||
* The difference between this method and {@link #getAnnotation(Class)}
|
||||
* is that this method detects if its argument is a <em>repeatable
|
||||
* annotation type</em>, and if so, attempts to find one or more
|
||||
* annotations of that type by "looking through" a container annotation.
|
||||
*
|
||||
* <p> The annotations returned by this method could contain an element
|
||||
* whose value is of type {@code Class}.
|
||||
* This value cannot be returned directly: information necessary to
|
||||
* locate and load a class (such as the class loader to use) is
|
||||
* not available, and the class might not be loadable at all.
|
||||
* Attempting to read a {@code Class} object by invoking the relevant
|
||||
* method on the returned annotation
|
||||
* will result in a {@link MirroredTypeException},
|
||||
* from which the corresponding {@link TypeMirror} may be extracted.
|
||||
* Similarly, attempting to read a {@code Class[]}-valued element
|
||||
* will result in a {@link MirroredTypesException}.
|
||||
*
|
||||
* <blockquote>
|
||||
* <i>Note:</i> This method is unlike others in this and related
|
||||
* interfaces. It operates on runtime reflective information —
|
||||
* representations of annotation types currently loaded into the
|
||||
* VM — rather than on the representations defined by and used
|
||||
* throughout these interfaces. Consequently, calling methods on
|
||||
* the returned annotation object can throw many of the exceptions
|
||||
* that can be thrown when calling methods on an annotation object
|
||||
* returned by core reflection. This method is intended for
|
||||
* callers that are written to operate on a known, fixed set of
|
||||
* annotation types.
|
||||
* </blockquote>
|
||||
*
|
||||
* @param <A> the annotation type
|
||||
* @param annotationType the {@code Class} object corresponding to
|
||||
* the annotation type
|
||||
* @return this construct's annotations for the specified annotation
|
||||
* type if present on this construct, else an empty array
|
||||
*
|
||||
* @see #getAnnotationMirrors()
|
||||
* @see #getAnnotation(Class)
|
||||
* @see java.lang.reflect.AnnotatedElement#getAnnotationsByType(Class)
|
||||
* @see EnumConstantNotPresentException
|
||||
* @see AnnotationTypeMismatchException
|
||||
* @see IncompleteAnnotationException
|
||||
* @see MirroredTypeException
|
||||
* @see MirroredTypesException
|
||||
* @jls 9.6 Annotation Interfaces
|
||||
* @jls 9.6.1 Annotation Interface Elements
|
||||
*/
|
||||
<A extends Annotation> A[] getAnnotationsByType(Class<A> annotationType);
|
||||
}
|
||||
@@ -0,0 +1,492 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import com.itsaky.androidide.config.JavacConfigProvider;
|
||||
|
||||
/**
|
||||
* Source versions of the Java programming language.
|
||||
*
|
||||
* See the appropriate edition of
|
||||
* <cite>The Java Language Specification</cite>
|
||||
* for information about a particular source version.
|
||||
*
|
||||
* <p>Note that additional source version constants will be added to
|
||||
* model future releases of the language.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @since 1.6
|
||||
*/
|
||||
public enum SourceVersion {
|
||||
/*
|
||||
* Summary of language evolution
|
||||
* 1.1: nested classes
|
||||
* 1.2: strictfp
|
||||
* 1.3: no changes
|
||||
* 1.4: assert
|
||||
* 1.5: annotations, generics, autoboxing, var-args...
|
||||
* 1.6: no changes
|
||||
* 1.7: diamond syntax, try-with-resources, etc.
|
||||
* 1.8: lambda expressions and default methods
|
||||
* 9: modules, small cleanups to 1.7 and 1.8 changes
|
||||
* 10: local-variable type inference (var)
|
||||
* 11: local-variable syntax for lambda parameters
|
||||
* 12: no changes (switch expressions in preview)
|
||||
* 13: no changes (switch expressions and text blocks in preview)
|
||||
* 14: switch expressions (pattern matching and records in
|
||||
* preview, text blocks in preview again)
|
||||
* 15: text blocks (records and pattern matching in preview again)
|
||||
*/
|
||||
|
||||
/**
|
||||
* The original version.
|
||||
*
|
||||
* The language described in
|
||||
* <cite>The Java Language Specification, First Edition</cite>.
|
||||
*/
|
||||
RELEASE_0,
|
||||
|
||||
/**
|
||||
* The version recognized by the Java Platform 1.1.
|
||||
*
|
||||
* The language is {@code RELEASE_0} augmented with nested classes as described in the 1.1 update to
|
||||
* <cite>The Java Language Specification, First Edition</cite>.
|
||||
*/
|
||||
RELEASE_1,
|
||||
|
||||
/**
|
||||
* The version recognized by the Java 2 Platform, Standard Edition,
|
||||
* v 1.2.
|
||||
*
|
||||
* The language described in
|
||||
* <cite>The Java Language Specification,
|
||||
* Second Edition</cite>, which includes the {@code
|
||||
* strictfp} modifier.
|
||||
*/
|
||||
RELEASE_2,
|
||||
|
||||
/**
|
||||
* The version recognized by the Java 2 Platform, Standard Edition,
|
||||
* v 1.3.
|
||||
*
|
||||
* No major changes from {@code RELEASE_2}.
|
||||
*/
|
||||
RELEASE_3,
|
||||
|
||||
/**
|
||||
* The version recognized by the Java 2 Platform, Standard Edition,
|
||||
* v 1.4.
|
||||
*
|
||||
* Added a simple assertion facility.
|
||||
*/
|
||||
RELEASE_4,
|
||||
|
||||
/**
|
||||
* The version recognized by the Java 2 Platform, Standard
|
||||
* Edition 5.0.
|
||||
*
|
||||
* The language described in
|
||||
* <cite>The Java Language Specification,
|
||||
* Third Edition</cite>. First release to support
|
||||
* generics, annotations, autoboxing, var-args, enhanced {@code
|
||||
* for} loop, and hexadecimal floating-point literals.
|
||||
*/
|
||||
RELEASE_5,
|
||||
|
||||
/**
|
||||
* The version recognized by the Java Platform, Standard Edition
|
||||
* 6.
|
||||
*
|
||||
* No major changes from {@code RELEASE_5}.
|
||||
*/
|
||||
RELEASE_6,
|
||||
|
||||
/**
|
||||
* The version recognized by the Java Platform, Standard Edition
|
||||
* 7.
|
||||
*
|
||||
* Additions in this release include, diamond syntax for
|
||||
* constructors, {@code try}-with-resources, strings in switch,
|
||||
* binary literals, and multi-catch.
|
||||
* @since 1.7
|
||||
*/
|
||||
RELEASE_7,
|
||||
|
||||
/**
|
||||
* The version recognized by the Java Platform, Standard Edition
|
||||
* 8.
|
||||
*
|
||||
* Additions in this release include lambda expressions and default methods.
|
||||
* @since 1.8
|
||||
*/
|
||||
RELEASE_8,
|
||||
|
||||
/**
|
||||
* The version recognized by the Java Platform, Standard Edition
|
||||
* 9.
|
||||
*
|
||||
* Additions in this release include modules and removal of a
|
||||
* single underscore from the set of legal identifier names.
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
RELEASE_9,
|
||||
|
||||
/**
|
||||
* The version recognized by the Java Platform, Standard Edition
|
||||
* 10.
|
||||
*
|
||||
* Additions in this release include local-variable type inference
|
||||
* ({@code var}).
|
||||
*
|
||||
* @since 10
|
||||
*/
|
||||
RELEASE_10,
|
||||
|
||||
/**
|
||||
* The version recognized by the Java Platform, Standard Edition
|
||||
* 11.
|
||||
*
|
||||
* Additions in this release include local-variable syntax for
|
||||
* lambda parameters.
|
||||
*
|
||||
* @since 11
|
||||
*/
|
||||
RELEASE_11,
|
||||
|
||||
/**
|
||||
* The version recognized by the Java Platform, Standard Edition
|
||||
* 12.
|
||||
*
|
||||
* @since 12
|
||||
*/
|
||||
RELEASE_12,
|
||||
|
||||
/**
|
||||
* The version recognized by the Java Platform, Standard Edition
|
||||
* 13.
|
||||
*
|
||||
* @since 13
|
||||
*/
|
||||
RELEASE_13,
|
||||
|
||||
/**
|
||||
* The version recognized by the Java Platform, Standard Edition
|
||||
* 14.
|
||||
*
|
||||
* Additions in this release include switch expressions.
|
||||
*
|
||||
* @since 14
|
||||
*/
|
||||
RELEASE_14,
|
||||
|
||||
/**
|
||||
* The version recognized by the Java Platform, Standard Edition
|
||||
* 15.
|
||||
*
|
||||
* Additions in this release include text blocks.
|
||||
*
|
||||
* @since 15
|
||||
*/
|
||||
RELEASE_15,
|
||||
|
||||
/**
|
||||
* The version recognized by the Java Platform, Standard Edition
|
||||
* 16.
|
||||
*
|
||||
* Additions in this release include pattern matching for {@code
|
||||
* instanceof} and records.
|
||||
*
|
||||
* @since 16
|
||||
*/
|
||||
RELEASE_16,
|
||||
|
||||
/**
|
||||
* The version recognized by the Java Platform, Standard Edition
|
||||
* 17.
|
||||
*
|
||||
* Additions in this release include sealed classes and
|
||||
* restoration of always-strict floating-point semantics.
|
||||
*
|
||||
* @since 17
|
||||
*/
|
||||
RELEASE_17;
|
||||
|
||||
// Note that when adding constants for newer releases, the
|
||||
// behavior of latest() and latestSupported() must be updated too.
|
||||
|
||||
/**
|
||||
* {@return the latest source version that can be modeled}
|
||||
*/
|
||||
public static SourceVersion latest() {
|
||||
// AndroidIDE changed: Allow overriding latest source version.
|
||||
return JavacConfigProvider.getLatestSourceVersion();
|
||||
}
|
||||
|
||||
private static final SourceVersion latestSupported = getLatestSupported();
|
||||
|
||||
/*
|
||||
* The integer version to enum constant mapping implemented by
|
||||
* this method assumes the JEP 322: "Time-Based Release
|
||||
* Versioning" scheme is in effect. This scheme began in JDK
|
||||
* 10. If the JDK versioning scheme is revised, this method may
|
||||
* need to be updated accordingly.
|
||||
*/
|
||||
private static SourceVersion getLatestSupported() {
|
||||
// AndroidIDE changed: Allow overriding latest supported source version.
|
||||
return JavacConfigProvider.getLatestSupportedSourceVersion();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* {@return the latest source version fully supported by the
|
||||
* current execution environment} {@code RELEASE_9} or later must
|
||||
|
||||
* be returned.
|
||||
*
|
||||
* @apiNote This method is included alongside {@link latest} to
|
||||
* allow identification of situations where the language model API
|
||||
* is running on a platform version different than the latest
|
||||
* version modeled by the API. One way that sort of situation can
|
||||
* occur is if an IDE or similar tool is using the API to model
|
||||
* source version <i>N</i> while running on platform version
|
||||
* (<i>N</i> - 1). Running in this configuration is
|
||||
* supported by the API. Running an API on platform versions
|
||||
* earlier than (<i>N</i> - 1) or later than <i>N</i>
|
||||
* may or may not work as an implementation detail. If an
|
||||
* annotation processor was generating code to run under the
|
||||
* current execution environment, the processor should only use
|
||||
* platform features up to the {@code latestSupported} release,
|
||||
* which may be earlier than the {@code latest} release.
|
||||
*/
|
||||
public static SourceVersion latestSupported() {
|
||||
// AndroidIDE changed: Allow overriding latest supported source version.
|
||||
return JavacConfigProvider.getLatestSupportedSourceVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not {@code name} is a syntactically valid
|
||||
* identifier (simple name) or keyword in the latest source
|
||||
* version. The method returns {@code true} if the name consists
|
||||
* of an initial character for which {@link
|
||||
* Character#isJavaIdentifierStart(int)} returns {@code true},
|
||||
* followed only by characters for which {@link
|
||||
* Character#isJavaIdentifierPart(int)} returns {@code true}.
|
||||
* This pattern matches regular identifiers, keywords, restricted
|
||||
* keywords, restricted identifiers and the literals {@code "true"},
|
||||
* {@code "false"}, {@code "null"}.
|
||||
*
|
||||
* The method returns {@code false} for all other strings.
|
||||
*
|
||||
* @param name the string to check
|
||||
* @return {@code true} if this string is a
|
||||
* syntactically valid identifier or keyword, {@code false}
|
||||
* otherwise.
|
||||
*
|
||||
* @jls 3.8 Identifiers
|
||||
*/
|
||||
public static boolean isIdentifier(CharSequence name) {
|
||||
String id = name.toString();
|
||||
|
||||
if (id.length() == 0) {
|
||||
return false;
|
||||
}
|
||||
int cp = id.codePointAt(0);
|
||||
if (!Character.isJavaIdentifierStart(cp)) {
|
||||
return false;
|
||||
}
|
||||
for (int i = Character.charCount(cp);
|
||||
i < id.length();
|
||||
i += Character.charCount(cp)) {
|
||||
cp = id.codePointAt(i);
|
||||
if (!Character.isJavaIdentifierPart(cp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not {@code name} is a syntactically valid
|
||||
* qualified name in the latest source version.
|
||||
*
|
||||
* Syntactically, a qualified name is a sequence of identifiers
|
||||
* separated by period characters ("{@code .}"). This method
|
||||
* splits the input string into period-separated segments and
|
||||
* applies checks to each segment in turn.
|
||||
*
|
||||
* Unlike {@link #isIdentifier isIdentifier}, this method returns
|
||||
* {@code false} for keywords, boolean literals, and the null
|
||||
* literal in any segment.
|
||||
*
|
||||
* This method returns {@code true} for <i>restricted
|
||||
* keywords</i> and <i>restricted identifiers</i>.
|
||||
*
|
||||
* @param name the string to check
|
||||
* @return {@code true} if this string is a
|
||||
* syntactically valid name, {@code false} otherwise.
|
||||
* @jls 3.9 Keywords
|
||||
* @jls 6.2 Names and Identifiers
|
||||
*/
|
||||
public static boolean isName(CharSequence name) {
|
||||
return isName(name, latest());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not {@code name} is a syntactically valid
|
||||
* qualified name in the given source version.
|
||||
*
|
||||
* Syntactically, a qualified name is a sequence of identifiers
|
||||
* separated by period characters ("{@code .}"). This method
|
||||
* splits the input string into period-separated segments and
|
||||
* applies checks to each segment in turn.
|
||||
*
|
||||
* Unlike {@link #isIdentifier isIdentifier}, this method returns
|
||||
* {@code false} for keywords, boolean literals, and the null
|
||||
* literal in any segment.
|
||||
*
|
||||
* This method returns {@code true} for <i>restricted
|
||||
* keywords</i> and <i>restricted identifiers</i>.
|
||||
*
|
||||
* @param name the string to check
|
||||
* @param version the version to use
|
||||
* @return {@code true} if this string is a
|
||||
* syntactically valid name, {@code false} otherwise.
|
||||
* @jls 3.9 Keywords
|
||||
* @jls 6.2 Names and Identifiers
|
||||
* @since 9
|
||||
*/
|
||||
public static boolean isName(CharSequence name, SourceVersion version) {
|
||||
String id = name.toString();
|
||||
|
||||
for(String s : id.split("\\.", -1)) {
|
||||
if (!isIdentifier(s) || isKeyword(s, version))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not {@code s} is a keyword, boolean literal,
|
||||
* or null literal in the latest source version.
|
||||
* This method returns {@code false} for <i>restricted
|
||||
* keywords</i> and <i>restricted identifiers</i>.
|
||||
*
|
||||
* @param s the string to check
|
||||
* @return {@code true} if {@code s} is a keyword, or boolean
|
||||
* literal, or null literal, {@code false} otherwise.
|
||||
* @jls 3.9 Keywords
|
||||
* @jls 3.10.3 Boolean Literals
|
||||
* @jls 3.10.8 The Null Literal
|
||||
*/
|
||||
public static boolean isKeyword(CharSequence s) {
|
||||
return isKeyword(s, latest());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not {@code s} is a keyword, boolean literal,
|
||||
* or null literal in the given source version.
|
||||
* This method returns {@code false} for <i>restricted
|
||||
* keywords</i> and <i>restricted identifiers</i>.
|
||||
*
|
||||
* @param s the string to check
|
||||
* @param version the version to use
|
||||
* @return {@code true} if {@code s} is a keyword, or boolean
|
||||
* literal, or null literal, {@code false} otherwise.
|
||||
* @jls 3.9 Keywords
|
||||
* @jls 3.10.3 Boolean Literals
|
||||
* @jls 3.10.8 The Null Literal
|
||||
* @since 9
|
||||
*/
|
||||
public static boolean isKeyword(CharSequence s, SourceVersion version) {
|
||||
String id = s.toString();
|
||||
switch(id) {
|
||||
// A trip through history
|
||||
case "strictfp":
|
||||
return version.compareTo(RELEASE_2) >= 0;
|
||||
|
||||
case "assert":
|
||||
return version.compareTo(RELEASE_4) >= 0;
|
||||
|
||||
case "enum":
|
||||
return version.compareTo(RELEASE_5) >= 0;
|
||||
|
||||
case "_":
|
||||
return version.compareTo(RELEASE_9) >= 0;
|
||||
|
||||
// case "non-sealed": can be added once it is a keyword only
|
||||
// dependent on release and not also preview features being
|
||||
// enabled.
|
||||
|
||||
// Keywords common across versions
|
||||
|
||||
// Modifiers
|
||||
case "public": case "protected": case "private":
|
||||
case "abstract": case "static": case "final":
|
||||
case "transient": case "volatile": case "synchronized":
|
||||
case "native":
|
||||
|
||||
// Declarations
|
||||
case "class": case "interface": case "extends":
|
||||
case "package": case "throws": case "implements":
|
||||
|
||||
// Primitive types and void
|
||||
case "boolean": case "byte": case "char":
|
||||
case "short": case "int": case "long":
|
||||
case "float": case "double":
|
||||
case "void":
|
||||
|
||||
// Control flow
|
||||
case "if": case "else":
|
||||
case "try": case "catch": case "finally":
|
||||
case "do": case "while":
|
||||
case "for": case "continue":
|
||||
case "switch": case "case": case "default":
|
||||
case "break": case "throw": case "return":
|
||||
|
||||
// Other keywords
|
||||
case "this": case "new": case "super":
|
||||
case "import": case "instanceof":
|
||||
|
||||
// Forbidden!
|
||||
case "goto": case "const":
|
||||
|
||||
// literals
|
||||
case "null": case "true": case "false":
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model;
|
||||
|
||||
/**
|
||||
* Superclass of exceptions which indicate that an unknown kind of
|
||||
* entity was encountered. This situation can occur if the language
|
||||
* evolves and new kinds of constructs are introduced. Subclasses of
|
||||
* this exception may be thrown by visitors to indicate that the
|
||||
* visitor was created for a prior version of the language.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @see jdkx.lang.model.element.UnknownElementException
|
||||
* @see jdkx.lang.model.element.UnknownAnnotationValueException
|
||||
* @see jdkx.lang.model.type.UnknownTypeException
|
||||
* @since 1.7
|
||||
*/
|
||||
public class UnknownEntityException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 269L;
|
||||
|
||||
/**
|
||||
* Creates a new {@code UnknownEntityException} with the specified
|
||||
* detail message.
|
||||
*
|
||||
* @param message the detail message
|
||||
*/
|
||||
protected UnknownEntityException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model.element;
|
||||
|
||||
import java.util.Map;
|
||||
import jdkx.lang.model.type.DeclaredType;
|
||||
|
||||
/**
|
||||
* Represents an annotation. An annotation associates a value with
|
||||
* each element of an annotation interface.
|
||||
*
|
||||
* <p> Annotations should be compared using the {@code equals}
|
||||
* method. There is no guarantee that any particular annotation will
|
||||
* always be represented by the same object.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @since 1.6
|
||||
*/
|
||||
public interface AnnotationMirror {
|
||||
|
||||
/**
|
||||
* {@return the type of this annotation}
|
||||
*/
|
||||
DeclaredType getAnnotationType();
|
||||
|
||||
/**
|
||||
* Returns the values of this annotation's elements.
|
||||
* This is returned in the form of a map that associates elements
|
||||
* with their corresponding values.
|
||||
* Only those elements with values explicitly present in the
|
||||
* annotation are included, not those that are implicitly assuming
|
||||
* their default values.
|
||||
* The order of the map matches the order in which the
|
||||
* values appear in the annotation's source.
|
||||
*
|
||||
* <p>Note that an annotation mirror of a marker annotation type
|
||||
* will by definition have an empty map.
|
||||
*
|
||||
* <p>To fill in default values, use {@link
|
||||
* jdkx.lang.model.util.Elements#getElementValuesWithDefaults
|
||||
* getElementValuesWithDefaults}.
|
||||
*
|
||||
* @return the values of this annotation's elements,
|
||||
* or an empty map if there are none
|
||||
*/
|
||||
Map<? extends ExecutableElement, ? extends AnnotationValue> getElementValues();
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model.element;
|
||||
|
||||
/**
|
||||
* Represents a value of an annotation interface element.
|
||||
* A value is of one of the following types:
|
||||
* <ul><li> a wrapper class (such as {@link Integer}) for a primitive type
|
||||
* <li> {@code String}
|
||||
* <li> {@code TypeMirror}
|
||||
* <li> {@code VariableElement} (representing an enum constant)
|
||||
* <li> {@code AnnotationMirror}
|
||||
* <li> {@code List<? extends AnnotationValue>}
|
||||
* (representing the elements, in declared order, if the value is an array)
|
||||
* </ul>
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @since 1.6
|
||||
*/
|
||||
public interface AnnotationValue {
|
||||
|
||||
/**
|
||||
* {@return the value}
|
||||
*/
|
||||
Object getValue();
|
||||
|
||||
/**
|
||||
* {@return a string representation of this value}
|
||||
* This is returned in a form suitable for representing this value
|
||||
* in the source code of an annotation.
|
||||
*/
|
||||
String toString();
|
||||
|
||||
/**
|
||||
* Applies a visitor to this value.
|
||||
*
|
||||
* @param <R> the return type of the visitor's methods
|
||||
* @param <P> the type of the additional parameter to the visitor's methods
|
||||
* @param v the visitor operating on this value
|
||||
* @param p additional parameter to the visitor
|
||||
* @return a visitor-specified result
|
||||
*/
|
||||
<R, P> R accept(AnnotationValueVisitor<R, P> v, P p);
|
||||
}
|
||||
+259
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model.element;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import jdkx.lang.model.type.TypeMirror;
|
||||
import jdkx.lang.model.util.*;
|
||||
|
||||
/**
|
||||
* A visitor of the values of annotation interface elements, using a
|
||||
* variant of the visitor design pattern. Unlike a standard visitor
|
||||
* which dispatches based on the concrete type of a member of a type
|
||||
* hierarchy, this visitor dispatches based on the type of data
|
||||
* stored; there are no distinct subclasses for storing, for example,
|
||||
* {@code boolean} values versus {@code int} values. Classes
|
||||
* implementing this interface are used to operate on a value when the
|
||||
* type of that value is unknown at compile time. When a visitor is
|
||||
* passed to a value's {@link AnnotationValue#accept accept} method,
|
||||
* the <code>visit<i>Xyz</i></code> method applicable to that value is
|
||||
* invoked.
|
||||
*
|
||||
* <p> Classes implementing this interface may or may not throw a
|
||||
* {@code NullPointerException} if the additional parameter {@code p}
|
||||
* is {@code null}; see documentation of the implementing class for
|
||||
* details.
|
||||
*
|
||||
* @apiNote
|
||||
* <strong>WARNING:</strong> It is possible that methods will be added
|
||||
* to this interface to accommodate new, currently unknown, language
|
||||
* structures added to future versions of the Java programming
|
||||
* language.
|
||||
*
|
||||
* Such additions have already occurred in another visitor interface in
|
||||
* this package to support language features added after this API was
|
||||
* introduced.
|
||||
*
|
||||
* Visitor classes directly implementing this interface may be source
|
||||
* incompatible with future versions of the platform. To avoid this
|
||||
* source incompatibility, visitor implementations are encouraged to
|
||||
* instead extend the appropriate abstract visitor class that
|
||||
* implements this interface. However, an API should generally use
|
||||
* this visitor interface as the type for parameters, return type,
|
||||
* etc. rather than one of the abstract classes.
|
||||
*
|
||||
* <p>Methods to accommodate new language constructs are expected to
|
||||
* be added as default methods to provide strong source compatibility,
|
||||
* as done for {@link ElementVisitor#visitModule visitModule} in
|
||||
* {@code ElementVisitor}. The implementations of the default methods
|
||||
* in this interface will in turn call {@link visitUnknown
|
||||
* visitUnknown}, behavior that will be overridden in concrete
|
||||
* visitors supporting the source version with the new language
|
||||
* construct.
|
||||
*
|
||||
* <p>There are several families of classes implementing this visitor
|
||||
* interface in the {@linkplain jdkx.lang.model.util util
|
||||
* package}. The families follow a naming pattern along the lines of
|
||||
* {@code FooVisitor}<i>N</i> where <i>N</i> indicates the
|
||||
* {@linkplain jdkx.lang.model.SourceVersion source version} the
|
||||
* visitor is appropriate for.
|
||||
*
|
||||
* In particular, a {@code FooVisitor}<i>N</i> is expected to handle
|
||||
* all language constructs present in source version <i>N</i>. If
|
||||
* there are no new language constructs added in version
|
||||
* <i>N</i> + 1 (or subsequent releases), {@code
|
||||
* FooVisitor}<i>N</i> may also handle that later source version; in
|
||||
* that case, the {@link
|
||||
* jdkx.annotation.processing.SupportedSourceVersion
|
||||
* SupportedSourceVersion} annotation on the {@code
|
||||
* FooVisitor}<i>N</i> class will indicate a later version.
|
||||
*
|
||||
* When visiting an annotation value representing a language construct
|
||||
* introduced <strong>after</strong> source version <i>N</i>, a {@code
|
||||
* FooVisitor}<i>N</i> will throw an {@link
|
||||
* UnknownAnnotationValueException} unless that behavior is overridden.
|
||||
*
|
||||
* <p>When choosing which member of a visitor family to subclass,
|
||||
* subclassing the most recent one increases the range of source
|
||||
* versions covered. When choosing which visitor family to subclass,
|
||||
* consider their built-in capabilities:
|
||||
*
|
||||
* <ul>
|
||||
*
|
||||
* <li>{@link AbstractAnnotationValueVisitor6
|
||||
* AbstractAnnotationValueVisitor}s: Skeletal visitor implementations.
|
||||
*
|
||||
* <li>{@link SimpleAnnotationValueVisitor6
|
||||
* SimpleAnnotationValueVisitor}s: Support default actions and a
|
||||
* default return value.
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* @param <R> the return type of this visitor's methods
|
||||
* @param <P> the type of the additional parameter to this visitor's methods.
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @since 1.6
|
||||
*/
|
||||
public interface AnnotationValueVisitor<R, P> {
|
||||
/**
|
||||
* Visits an annotation value.
|
||||
* @param av the value to visit
|
||||
* @param p a visitor-specified parameter
|
||||
* @return a visitor-specified result
|
||||
*/
|
||||
R visit(AnnotationValue av, P p);
|
||||
|
||||
/**
|
||||
* A convenience method equivalent to {@code visit(av, null)}.
|
||||
*
|
||||
* @implSpec The default implementation is {@code visit(av, null)}.
|
||||
*
|
||||
* @param av the value to visit
|
||||
* @return a visitor-specified result
|
||||
*/
|
||||
default R visit(AnnotationValue av) {
|
||||
return visit(av, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a {@code boolean} value in an annotation.
|
||||
* @param b the value being visited
|
||||
* @param p a visitor-specified parameter
|
||||
* @return the result of the visit
|
||||
*/
|
||||
R visitBoolean(boolean b, P p);
|
||||
|
||||
/**
|
||||
* Visits a {@code byte} value in an annotation.
|
||||
* @param b the value being visited
|
||||
* @param p a visitor-specified parameter
|
||||
* @return the result of the visit
|
||||
*/
|
||||
R visitByte(byte b, P p);
|
||||
|
||||
/**
|
||||
* Visits a {@code char} value in an annotation.
|
||||
* @param c the value being visited
|
||||
* @param p a visitor-specified parameter
|
||||
* @return the result of the visit
|
||||
*/
|
||||
R visitChar(char c, P p);
|
||||
|
||||
/**
|
||||
* Visits a {@code double} value in an annotation.
|
||||
* @param d the value being visited
|
||||
* @param p a visitor-specified parameter
|
||||
* @return the result of the visit
|
||||
*/
|
||||
R visitDouble(double d, P p);
|
||||
|
||||
/**
|
||||
* Visits a {@code float} value in an annotation.
|
||||
* @param f the value being visited
|
||||
* @param p a visitor-specified parameter
|
||||
* @return the result of the visit
|
||||
*/
|
||||
R visitFloat(float f, P p);
|
||||
|
||||
/**
|
||||
* Visits an {@code int} value in an annotation.
|
||||
* @param i the value being visited
|
||||
* @param p a visitor-specified parameter
|
||||
* @return the result of the visit
|
||||
*/
|
||||
R visitInt(int i, P p);
|
||||
|
||||
/**
|
||||
* Visits a {@code long} value in an annotation.
|
||||
* @param i the value being visited
|
||||
* @param p a visitor-specified parameter
|
||||
* @return the result of the visit
|
||||
*/
|
||||
R visitLong(long i, P p);
|
||||
|
||||
/**
|
||||
* Visits a {@code short} value in an annotation.
|
||||
* @param s the value being visited
|
||||
* @param p a visitor-specified parameter
|
||||
* @return the result of the visit
|
||||
*/
|
||||
R visitShort(short s, P p);
|
||||
|
||||
/**
|
||||
* Visits a string value in an annotation.
|
||||
* @param s the value being visited
|
||||
* @param p a visitor-specified parameter
|
||||
* @return the result of the visit
|
||||
*/
|
||||
R visitString(String s, P p);
|
||||
|
||||
/**
|
||||
* Visits a type value in an annotation.
|
||||
* @param t the value being visited
|
||||
* @param p a visitor-specified parameter
|
||||
* @return the result of the visit
|
||||
*/
|
||||
R visitType(TypeMirror t, P p);
|
||||
|
||||
/**
|
||||
* Visits an {@code enum} value in an annotation.
|
||||
* @param c the value being visited
|
||||
* @param p a visitor-specified parameter
|
||||
* @return the result of the visit
|
||||
*/
|
||||
R visitEnumConstant(VariableElement c, P p);
|
||||
|
||||
/**
|
||||
* Visits an annotation value in an annotation.
|
||||
* @param a the value being visited
|
||||
* @param p a visitor-specified parameter
|
||||
* @return the result of the visit
|
||||
*/
|
||||
R visitAnnotation(AnnotationMirror a, P p);
|
||||
|
||||
/**
|
||||
* Visits an array value in an annotation.
|
||||
* @param vals the value being visited
|
||||
* @param p a visitor-specified parameter
|
||||
* @return the result of the visit
|
||||
*/
|
||||
R visitArray(List<? extends AnnotationValue> vals, P p);
|
||||
|
||||
/**
|
||||
* Visits an unknown kind of annotation value.
|
||||
* This can occur if the language evolves and new kinds
|
||||
* of value can be stored in an annotation.
|
||||
* @param av the unknown value being visited
|
||||
* @param p a visitor-specified parameter
|
||||
* @return the result of the visit
|
||||
* @throws UnknownAnnotationValueException
|
||||
* a visitor implementation may optionally throw this exception
|
||||
*/
|
||||
R visitUnknown(AnnotationValue av, P p);
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model.element;
|
||||
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.AnnotationTypeMismatchException;
|
||||
import java.lang.annotation.IncompleteAnnotationException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import jdkx.lang.model.type.*;
|
||||
import jdkx.lang.model.util.*;
|
||||
|
||||
/**
|
||||
* Represents a program element such as a module, package, class, or method.
|
||||
* Each element represents a compile-time language-level construct
|
||||
* (and not, for example, a runtime construct of the virtual machine).
|
||||
*
|
||||
* <p> Elements should be compared using the {@link #equals(Object)}
|
||||
* method. There is no guarantee that any particular element will
|
||||
* always be represented by the same object.
|
||||
*
|
||||
* <p> To implement operations based on the class of an {@code
|
||||
* Element} object, either use a {@linkplain ElementVisitor visitor} or
|
||||
* use the result of the {@link #getKind} method. Using {@code
|
||||
* instanceof} is <em>not</em> necessarily a reliable idiom for
|
||||
* determining the effective class of an object in this modeling
|
||||
* hierarchy since an implementation may choose to have a single object
|
||||
* implement multiple {@code Element} subinterfaces.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @see Elements
|
||||
* @see TypeMirror
|
||||
* @since 1.6
|
||||
*/
|
||||
public interface Element extends jdkx.lang.model.AnnotatedConstruct {
|
||||
/**
|
||||
* {@return the type defined by this element}
|
||||
*
|
||||
* @see Types
|
||||
* @see ExecutableElement#asType
|
||||
* @see ModuleElement#asType
|
||||
* @see PackageElement#asType
|
||||
* @see TypeElement#asType
|
||||
* @see TypeParameterElement#asType
|
||||
* @see VariableElement#asType
|
||||
*/
|
||||
TypeMirror asType();
|
||||
|
||||
/**
|
||||
* {@return the {@code kind} of this element}
|
||||
*
|
||||
* <ul>
|
||||
*
|
||||
* <li> The kind of a {@linkplain PackageElement package} is
|
||||
* {@link ElementKind#PACKAGE PACKAGE}.
|
||||
*
|
||||
* <li> The kind of a {@linkplain ModuleElement module} is {@link
|
||||
* ElementKind#MODULE MODULE}.
|
||||
*
|
||||
* <li> The kind of a {@linkplain TypeElement type element} is one
|
||||
* of {@link ElementKind#ANNOTATION_TYPE ANNOTATION_TYPE}, {@link
|
||||
* ElementKind#CLASS CLASS}, {@link ElementKind#ENUM ENUM}, {@link
|
||||
* ElementKind#INTERFACE INTERFACE}, or {@link ElementKind#RECORD
|
||||
* RECORD}.
|
||||
*
|
||||
* <li> The kind of a {@linkplain VariableElement variable} is one
|
||||
* of {@link ElementKind#ENUM_CONSTANT ENUM_CONSTANT}, {@link
|
||||
* ElementKind#EXCEPTION_PARAMETER EXCEPTION_PARAMETER}, {@link
|
||||
* ElementKind#FIELD FIELD}, {@link ElementKind#LOCAL_VARIABLE
|
||||
* LOCAL_VARIABLE}, {@link ElementKind#PARAMETER PARAMETER},
|
||||
* {@link ElementKind#RESOURCE_VARIABLE RESOURCE_VARIABLE}, or
|
||||
* {@link ElementKind#BINDING_VARIABLE BINDING_VARIABLE}.
|
||||
*
|
||||
* <li> The kind of an {@linkplain ExecutableElement executable}
|
||||
* is one of {@link ElementKind#CONSTRUCTOR CONSTRUCTOR}, {@link
|
||||
* ElementKind#INSTANCE_INIT INSTANCE_INIT}, {@link
|
||||
* ElementKind#METHOD METHOD}, or {@link ElementKind#STATIC_INIT
|
||||
* STATIC_INIT}.
|
||||
*
|
||||
* <li> The kind of a {@linkplain TypeParameterElement type parameter} is
|
||||
* {@link ElementKind#TYPE_PARAMETER TYPE_PARAMETER}.
|
||||
*
|
||||
* <li> The kind of a {@linkplain RecordComponentElement record
|
||||
* component} is {@link ElementKind#RECORD_COMPONENT
|
||||
* RECORD_COMPONENT}.
|
||||
*
|
||||
* </ul>
|
||||
*/
|
||||
ElementKind getKind();
|
||||
|
||||
/**
|
||||
* Returns the modifiers of this element, excluding annotations.
|
||||
* Implicit modifiers, such as the {@code public} and {@code static}
|
||||
* modifiers of interface members, are included.
|
||||
*
|
||||
* @return the modifiers of this element, or an empty set if there are none
|
||||
*/
|
||||
Set<Modifier> getModifiers();
|
||||
|
||||
/**
|
||||
* {@return the simple (unqualified) name of this element} The
|
||||
* name of a generic class or interface does not include any
|
||||
* reference to its formal type parameters.
|
||||
*
|
||||
* For example, the simple name of the type element representing
|
||||
* {@code java.util.Set<E>} is {@code "Set"}.
|
||||
*
|
||||
* If this element represents an unnamed {@linkplain
|
||||
* PackageElement#getSimpleName package} or unnamed {@linkplain
|
||||
* ModuleElement#getSimpleName module}, an <a
|
||||
* href=Name.html#empty_name>empty name</a> is returned.
|
||||
*
|
||||
* If it represents a {@linkplain ExecutableElement#getSimpleName
|
||||
* constructor}, the name "{@code <init>}" is returned. If it
|
||||
* represents a {@linkplain ExecutableElement#getSimpleName static
|
||||
* initializer}, the name "{@code <clinit>}" is returned.
|
||||
*
|
||||
* If it represents an {@linkplain TypeElement#getSimpleName
|
||||
* anonymous class} or {@linkplain ExecutableElement#getSimpleName
|
||||
* instance initializer}, an <a href=Name.html#empty_name>empty
|
||||
* name</a> is returned.
|
||||
*
|
||||
* @see PackageElement#getSimpleName
|
||||
* @see ExecutableElement#getSimpleName
|
||||
* @see TypeElement#getSimpleName
|
||||
* @see VariableElement#getSimpleName
|
||||
* @see ModuleElement#getSimpleName
|
||||
* @see RecordComponentElement#getSimpleName
|
||||
* @revised 9
|
||||
*/
|
||||
Name getSimpleName();
|
||||
|
||||
/**
|
||||
* Returns the innermost element
|
||||
* within which this element is, loosely speaking, enclosed.
|
||||
* <ul>
|
||||
* <li> If this element is one whose declaration is lexically enclosed
|
||||
* immediately within the declaration of another element, that other
|
||||
* element is returned.
|
||||
*
|
||||
* <li> If this is a {@linkplain TypeElement#getEnclosingElement
|
||||
* top-level class or interface}, its package is returned.
|
||||
*
|
||||
* <li> If this is a {@linkplain
|
||||
* PackageElement#getEnclosingElement package}, its module is
|
||||
* returned if such a module exists. Otherwise, {@code null} is returned.
|
||||
*
|
||||
* <li> If this is a {@linkplain
|
||||
* TypeParameterElement#getEnclosingElement type parameter},
|
||||
* {@linkplain TypeParameterElement#getGenericElement the
|
||||
* generic element} of the type parameter is returned.
|
||||
*
|
||||
* <li> If this is a {@linkplain
|
||||
* VariableElement#getEnclosingElement method or constructor
|
||||
* parameter}, {@linkplain ExecutableElement the executable
|
||||
* element} which declares the parameter is returned.
|
||||
*
|
||||
* <li> If this is a {@linkplain
|
||||
* RecordComponentElement#getEnclosingElement record component},
|
||||
* {@linkplain TypeElement the record class} which declares the
|
||||
* record component is returned.
|
||||
*
|
||||
* <li> If this is a {@linkplain ModuleElement#getEnclosingElement
|
||||
* module}, {@code null} is returned.
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* @return the enclosing element, or {@code null} if there is none
|
||||
* @see Elements#getPackageOf
|
||||
* @revised 9
|
||||
*/
|
||||
Element getEnclosingElement();
|
||||
|
||||
/**
|
||||
* Returns the elements that are, loosely speaking, directly
|
||||
* enclosed by this element.
|
||||
*
|
||||
* A {@linkplain TypeElement#getEnclosedElements class or
|
||||
* interface} is considered to enclose the fields, methods,
|
||||
* constructors, record components, and member classes and interfaces that it directly declares.
|
||||
*
|
||||
* A {@linkplain PackageElement#getEnclosedElements package}
|
||||
* encloses the top-level classes and interfaces within it, but is
|
||||
* not considered to enclose subpackages.
|
||||
*
|
||||
* A {@linkplain ModuleElement#getEnclosedElements module}
|
||||
* encloses packages within it.
|
||||
*
|
||||
* Enclosed elements may include implicitly declared {@linkplain
|
||||
* Elements.Origin#MANDATED mandated} elements.
|
||||
*
|
||||
* Other kinds of elements are not currently considered to enclose
|
||||
* any elements; however, that may change as this API or the
|
||||
* programming language evolves.
|
||||
*
|
||||
* @apiNote Elements of certain kinds can be isolated using
|
||||
* methods in {@link ElementFilter}.
|
||||
*
|
||||
* @return the enclosed elements, or an empty list if none
|
||||
* @see TypeElement#getEnclosedElements
|
||||
* @see PackageElement#getEnclosedElements
|
||||
* @see ModuleElement#getEnclosedElements
|
||||
* @see Elements#getAllMembers
|
||||
* @jls 8.8.9 Default Constructor
|
||||
* @jls 8.9 Enum Classes
|
||||
* @revised 9
|
||||
*/
|
||||
List<? extends Element> getEnclosedElements();
|
||||
|
||||
/**
|
||||
* {@return {@code true} if the argument represents the same
|
||||
* element as {@code this}, or {@code false} otherwise}
|
||||
*
|
||||
* @apiNote The identity of an element involves implicit state
|
||||
* not directly accessible from the element's methods, including
|
||||
* state about the presence of unrelated types. Element objects
|
||||
* created by different implementations of these interfaces should
|
||||
* <i>not</i> be expected to be equal even if "the same"
|
||||
* element is being modeled; this is analogous to the inequality
|
||||
* of {@code Class} objects for the same class file loaded through
|
||||
* different class loaders.
|
||||
*
|
||||
* @param obj the object to be compared with this element
|
||||
*/
|
||||
@Override
|
||||
boolean equals(Object obj);
|
||||
|
||||
/**
|
||||
* Obeys the general contract of {@link Object#hashCode Object.hashCode}.
|
||||
*
|
||||
* @see #equals
|
||||
*/
|
||||
@Override
|
||||
int hashCode();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>To get inherited annotations as well, use {@link
|
||||
* Elements#getAllAnnotationMirrors(Element)
|
||||
* getAllAnnotationMirrors}.
|
||||
*
|
||||
* <p>Note that any annotations returned by this method are
|
||||
* declaration annotations.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
@Override
|
||||
List<? extends AnnotationMirror> getAnnotationMirrors();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>Note that any annotation returned by this method is a
|
||||
* declaration annotation.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
@Override
|
||||
<A extends Annotation> A getAnnotation(Class<A> annotationType);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>Note that any annotations returned by this method are
|
||||
* declaration annotations.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
@Override
|
||||
<A extends Annotation> A[] getAnnotationsByType(Class<A> annotationType);
|
||||
|
||||
/**
|
||||
* Applies a visitor to this element.
|
||||
*
|
||||
* @param <R> the return type of the visitor's methods
|
||||
* @param <P> the type of the additional parameter to the visitor's methods
|
||||
* @param v the visitor operating on this element
|
||||
* @param p additional parameter to the visitor
|
||||
* @return a visitor-specified result
|
||||
*/
|
||||
<R, P> R accept(ElementVisitor<R, P> v, P p);
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model.element;
|
||||
|
||||
/**
|
||||
* The {@code kind} of an element.
|
||||
*
|
||||
* <p>Note that it is possible additional element kinds will be added
|
||||
* to accommodate new, currently unknown, language structures added to
|
||||
* future versions of the Java programming language.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @see Element
|
||||
* @since 1.6
|
||||
*/
|
||||
public enum ElementKind {
|
||||
|
||||
/** A package. */
|
||||
PACKAGE,
|
||||
|
||||
// Declared types
|
||||
/** An enum class. */
|
||||
ENUM,
|
||||
/**
|
||||
* A class not described by a more specific kind (like {@code
|
||||
* ENUM} or {@code RECORD}).
|
||||
*/
|
||||
CLASS,
|
||||
|
||||
/** An annotation interface. (Formerly known as an annotation type.) */
|
||||
ANNOTATION_TYPE,
|
||||
/**
|
||||
* An interface not described by a more specific kind (like
|
||||
* {@code ANNOTATION_TYPE}).
|
||||
*/
|
||||
INTERFACE,
|
||||
|
||||
// Variables
|
||||
/** An enum constant. */
|
||||
ENUM_CONSTANT,
|
||||
/**
|
||||
* A field not described by a more specific kind (like
|
||||
* {@code ENUM_CONSTANT}).
|
||||
*/
|
||||
FIELD,
|
||||
/** A parameter of a method or constructor. */
|
||||
PARAMETER,
|
||||
/** A local variable. */
|
||||
LOCAL_VARIABLE,
|
||||
/** A parameter of an exception handler. */
|
||||
EXCEPTION_PARAMETER,
|
||||
|
||||
// Executables
|
||||
/** A method. */
|
||||
METHOD,
|
||||
/** A constructor. */
|
||||
CONSTRUCTOR,
|
||||
/** A static initializer. */
|
||||
STATIC_INIT,
|
||||
/** An instance initializer. */
|
||||
INSTANCE_INIT,
|
||||
|
||||
/** A type parameter. */
|
||||
TYPE_PARAMETER,
|
||||
|
||||
/**
|
||||
* An implementation-reserved element. This is not the element
|
||||
* you are looking for.
|
||||
*/
|
||||
OTHER,
|
||||
|
||||
// Constants added since initial release
|
||||
|
||||
/**
|
||||
* A resource variable.
|
||||
* @since 1.7
|
||||
*/
|
||||
RESOURCE_VARIABLE,
|
||||
|
||||
/**
|
||||
* A module.
|
||||
* @since 9
|
||||
*/
|
||||
MODULE,
|
||||
|
||||
/**
|
||||
* A record class.
|
||||
* @since 16
|
||||
*/
|
||||
RECORD,
|
||||
|
||||
/**
|
||||
* A record component of a {@code record}.
|
||||
* @since 16
|
||||
*/
|
||||
RECORD_COMPONENT,
|
||||
|
||||
/**
|
||||
* A binding variable in a pattern.
|
||||
* @since 16
|
||||
*/
|
||||
BINDING_VARIABLE;
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this is a kind of class:
|
||||
* either {@code CLASS} or {@code ENUM} or {@code RECORD}.
|
||||
*
|
||||
* @return {@code true} if this is a kind of class
|
||||
*/
|
||||
@SuppressWarnings("preview")
|
||||
public boolean isClass() {
|
||||
return this == CLASS || this == ENUM || this == RECORD;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this is a kind of interface:
|
||||
* either {@code INTERFACE} or {@code ANNOTATION_TYPE}.
|
||||
*
|
||||
* @return {@code true} if this is a kind of interface
|
||||
*/
|
||||
public boolean isInterface() {
|
||||
return this == INTERFACE || this == ANNOTATION_TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this is a kind of field:
|
||||
* either {@code FIELD} or {@code ENUM_CONSTANT}.
|
||||
*
|
||||
* @return {@code true} if this is a kind of field
|
||||
*/
|
||||
public boolean isField() {
|
||||
return this == FIELD || this == ENUM_CONSTANT;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model.element;
|
||||
|
||||
import jdkx.lang.model.util.*;
|
||||
|
||||
/**
|
||||
* A visitor of program elements, in the style of the visitor design
|
||||
* pattern. Classes implementing this interface are used to operate
|
||||
* on an element when the kind of element is unknown at compile time.
|
||||
* When a visitor is passed to an element's {@link Element#accept
|
||||
* accept} method, the <code>visit<i>Xyz</i></code> method most applicable
|
||||
* to that element is invoked.
|
||||
*
|
||||
* <p> Classes implementing this interface may or may not throw a
|
||||
* {@code NullPointerException} if the additional parameter {@code p}
|
||||
* is {@code null}; see documentation of the implementing class for
|
||||
* details.
|
||||
*
|
||||
* @apiNote
|
||||
* <strong>WARNING:</strong> It is possible that methods will be added
|
||||
* to this interface to accommodate new, currently unknown, language
|
||||
* structures added to future versions of the Java programming
|
||||
* language.
|
||||
*
|
||||
* Such additions have already occurred to support language features
|
||||
* added after this API was introduced.
|
||||
*
|
||||
* Visitor classes directly implementing this interface may be source
|
||||
* incompatible with future versions of the platform. To avoid this
|
||||
* source incompatibility, visitor implementations are encouraged to
|
||||
* instead extend the appropriate abstract visitor class that
|
||||
* implements this interface. However, an API should generally use
|
||||
* this visitor interface as the type for parameters, return type,
|
||||
* etc. rather than one of the abstract classes.
|
||||
*
|
||||
* <p>Methods to accommodate new language constructs are expected to
|
||||
* be added as default methods to provide strong source compatibility,
|
||||
* as done for {@link visitModule visitModule}. The implementations of
|
||||
* the default methods will in turn call {@link visitUnknown
|
||||
* visitUnknown}, behavior that will be overridden in concrete
|
||||
* visitors supporting the source version with the new language
|
||||
* construct.
|
||||
*
|
||||
* <p>There are several families of classes implementing this visitor
|
||||
* interface in the {@linkplain jdkx.lang.model.util util
|
||||
* package}. The families follow a naming pattern along the lines of
|
||||
* {@code FooVisitor}<i>N</i> where <i>N</i> indicates the
|
||||
* {@linkplain jdkx.lang.model.SourceVersion source version} the
|
||||
* visitor is appropriate for.
|
||||
*
|
||||
* In particular, a {@code FooVisitor}<i>N</i> is expected to handle
|
||||
* all language constructs present in source version <i>N</i>. If
|
||||
* there are no new language constructs added in version
|
||||
* <i>N</i> + 1 (or subsequent releases), {@code
|
||||
* FooVisitor}<i>N</i> may also handle that later source version; in
|
||||
* that case, the {@link
|
||||
* jdkx.annotation.processing.SupportedSourceVersion
|
||||
* SupportedSourceVersion} annotation on the {@code
|
||||
* FooVisitor}<i>N</i> class will indicate a later version.
|
||||
*
|
||||
* When visiting an element representing a language construct
|
||||
* introduced <strong>after</strong> source version <i>N</i>, a {@code
|
||||
* FooVisitor}<i>N</i> will throw an {@link UnknownElementException}
|
||||
* unless that behavior is overridden.
|
||||
*
|
||||
* <p>When choosing which member of a visitor family to subclass,
|
||||
* subclassing the most recent one increases the range of source
|
||||
* versions covered. When choosing which visitor family to subclass,
|
||||
* consider their built-in capabilities:
|
||||
*
|
||||
* <ul>
|
||||
*
|
||||
* <li>{@link AbstractElementVisitor6 AbstractElementVisitor}s:
|
||||
* Skeletal visitor implementations.
|
||||
*
|
||||
* <li>{@link SimpleElementVisitor6 SimpleElementVisitor}s: Support
|
||||
* default actions and a default return value.
|
||||
*
|
||||
* <li>{@link ElementKindVisitor6 ElementKindVisitor}s: Visit methods
|
||||
* provided on a {@linkplain Element#getKind per-kind} granularity as
|
||||
* some categories of elements can have more than one kind.
|
||||
*
|
||||
* <li>{@link ElementScanner6 ElementScanner}s: Scanners are visitors
|
||||
* which traverse an element and the elements {@linkplain
|
||||
* Element#getEnclosedElements enclosed} by it and associated with it.
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* @param <R> the return type of this visitor's methods. Use {@link
|
||||
* Void} for visitors that do not need to return results.
|
||||
* @param <P> the type of the additional parameter to this visitor's
|
||||
* methods. Use {@code Void} for visitors that do not need an
|
||||
* additional parameter.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @since 1.6
|
||||
*/
|
||||
public interface ElementVisitor<R, P> {
|
||||
/**
|
||||
* Visits an element.
|
||||
* @param e the element to visit
|
||||
* @param p a visitor-specified parameter
|
||||
* @return a visitor-specified result
|
||||
*/
|
||||
R visit(Element e, P p);
|
||||
|
||||
/**
|
||||
* A convenience method equivalent to {@code visit(e, null)}.
|
||||
*
|
||||
* @implSpec The default implementation is {@code visit(e, null)}.
|
||||
*
|
||||
* @param e the element to visit
|
||||
* @return a visitor-specified result
|
||||
*/
|
||||
default R visit(Element e) {
|
||||
return visit(e, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a package element.
|
||||
* @param e the element to visit
|
||||
* @param p a visitor-specified parameter
|
||||
* @return a visitor-specified result
|
||||
*/
|
||||
R visitPackage(PackageElement e, P p);
|
||||
|
||||
/**
|
||||
* Visits a type element.
|
||||
* @param e the element to visit
|
||||
* @param p a visitor-specified parameter
|
||||
* @return a visitor-specified result
|
||||
*/
|
||||
R visitType(TypeElement e, P p);
|
||||
|
||||
/**
|
||||
* Visits a variable element.
|
||||
* @param e the element to visit
|
||||
* @param p a visitor-specified parameter
|
||||
* @return a visitor-specified result
|
||||
*/
|
||||
R visitVariable(VariableElement e, P p);
|
||||
|
||||
/**
|
||||
* Visits an executable element.
|
||||
* @param e the element to visit
|
||||
* @param p a visitor-specified parameter
|
||||
* @return a visitor-specified result
|
||||
*/
|
||||
R visitExecutable(ExecutableElement e, P p);
|
||||
|
||||
/**
|
||||
* Visits a type parameter element.
|
||||
* @param e the element to visit
|
||||
* @param p a visitor-specified parameter
|
||||
* @return a visitor-specified result
|
||||
*/
|
||||
R visitTypeParameter(TypeParameterElement e, P p);
|
||||
|
||||
/**
|
||||
* Visits an unknown kind of element.
|
||||
* This can occur if the language evolves and new kinds
|
||||
* of elements are added to the {@code Element} hierarchy.
|
||||
*
|
||||
* @param e the element to visit
|
||||
* @param p a visitor-specified parameter
|
||||
* @return a visitor-specified result
|
||||
* @throws UnknownElementException
|
||||
* a visitor implementation may optionally throw this exception
|
||||
*/
|
||||
R visitUnknown(Element e, P p);
|
||||
|
||||
/**
|
||||
* Visits a module element.
|
||||
*
|
||||
* @implSpec The default implementation visits a {@code
|
||||
* ModuleElement} by calling {@code visitUnknown(e, p)}.
|
||||
*
|
||||
* @param e the element to visit
|
||||
* @param p a visitor-specified parameter
|
||||
* @return a visitor-specified result
|
||||
* @since 9
|
||||
*/
|
||||
default R visitModule(ModuleElement e, P p) {
|
||||
return visitUnknown(e, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a record component element.
|
||||
*
|
||||
* @implSpec The default implementation visits a {@code
|
||||
* RecordComponentElement} by calling {@code visitUnknown(e, p)}.
|
||||
*
|
||||
* @param e the element to visit
|
||||
* @param p a visitor-specified parameter
|
||||
* @return a visitor-specified result
|
||||
* @since 16
|
||||
*/
|
||||
default R visitRecordComponent(RecordComponentElement e, P p) {
|
||||
return visitUnknown(e, p);
|
||||
}
|
||||
}
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model.element;
|
||||
|
||||
import java.util.List;
|
||||
import jdkx.lang.model.type.*;
|
||||
|
||||
/**
|
||||
* Represents a method, constructor, or initializer (static or
|
||||
* instance) of a class or interface, including annotation type
|
||||
* elements.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @see ExecutableType
|
||||
* @since 1.6
|
||||
*/
|
||||
public interface ExecutableElement extends Element, Parameterizable {
|
||||
/**
|
||||
* {@return the {@linkplain ExecutableType executable type} defined
|
||||
* by this executable element}
|
||||
*
|
||||
* @see ExecutableType
|
||||
*/
|
||||
@Override
|
||||
TypeMirror asType();
|
||||
|
||||
/**
|
||||
* Returns the formal type parameters of this executable
|
||||
* in declaration order.
|
||||
*
|
||||
* @return the formal type parameters, or an empty list
|
||||
* if there are none
|
||||
*/
|
||||
List<? extends TypeParameterElement> getTypeParameters();
|
||||
|
||||
/**
|
||||
* {@return the return type of this executable}
|
||||
* Returns a {@link NoType} with kind {@link TypeKind#VOID VOID}
|
||||
* if this executable is not a method, or is a method that does not
|
||||
* return a value.
|
||||
*/
|
||||
TypeMirror getReturnType();
|
||||
|
||||
/**
|
||||
* Returns the formal parameters of this executable.
|
||||
* They are returned in declaration order.
|
||||
*
|
||||
* @return the formal parameters,
|
||||
* or an empty list if there are none
|
||||
*/
|
||||
List<? extends VariableElement> getParameters();
|
||||
|
||||
/**
|
||||
* Returns the receiver type of this executable,
|
||||
* or {@link jdkx.lang.model.type.NoType NoType} with
|
||||
* kind {@link jdkx.lang.model.type.TypeKind#NONE NONE}
|
||||
* if the executable has no receiver type.
|
||||
*
|
||||
* An executable which is an instance method, or a constructor of an
|
||||
* inner class, has a receiver type derived from the {@linkplain
|
||||
* #getEnclosingElement declaring type}.
|
||||
*
|
||||
* An executable which is a static method, or a constructor of a
|
||||
* non-inner class, or an initializer (static or instance), has no
|
||||
* receiver type.
|
||||
*
|
||||
* @return the receiver type of this executable
|
||||
* @since 1.8
|
||||
*
|
||||
* @jls 8.4 Method Declarations
|
||||
* @jls 8.4.1 Formal Parameters
|
||||
* @jls 8.8 Constructor Declarations
|
||||
*/
|
||||
TypeMirror getReceiverType();
|
||||
|
||||
/**
|
||||
* {@return {@code true} if this method or constructor accepts a variable
|
||||
* number of arguments and returns {@code false} otherwise}
|
||||
*/
|
||||
boolean isVarArgs();
|
||||
|
||||
/**
|
||||
* {@return {@code true} if this method is a default method and
|
||||
* returns {@code false} otherwise}
|
||||
* @since 1.8
|
||||
*/
|
||||
boolean isDefault();
|
||||
|
||||
/**
|
||||
* Returns the exceptions and other throwables listed in this
|
||||
* method or constructor's {@code throws} clause in declaration
|
||||
* order.
|
||||
*
|
||||
* @return the exceptions and other throwables listed in the
|
||||
* {@code throws} clause, or an empty list if there are none
|
||||
*/
|
||||
List<? extends TypeMirror> getThrownTypes();
|
||||
|
||||
/**
|
||||
* Returns the default value if this executable is an annotation
|
||||
* interface element. Returns {@code null} if this method is not
|
||||
* an annotation interface element, or if it is an annotation
|
||||
* interface element with no default value.
|
||||
*
|
||||
* @return the default value, or {@code null} if none
|
||||
*/
|
||||
AnnotationValue getDefaultValue();
|
||||
|
||||
/**
|
||||
* {@return the simple name of a constructor, method, or
|
||||
* initializer} For a constructor, the name {@code "<init>"} is
|
||||
* returned, for a static initializer, the name {@code "<clinit>"}
|
||||
* is returned, and for an anonymous class or instance
|
||||
* initializer, an <a href=Name.html#empty_name>empty name</a> is
|
||||
* returned.
|
||||
*/
|
||||
@Override
|
||||
Name getSimpleName();
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model.element;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a modifier on a program element such
|
||||
* as a class, method, or field.
|
||||
*
|
||||
* <p>Not all modifiers are applicable to all kinds of elements.
|
||||
* When two or more modifiers appear in the source code of an element
|
||||
* then it is customary, though not required, that they appear in the same
|
||||
* order as the constants listed in the detail section below.
|
||||
*
|
||||
* <p>Note that it is possible additional modifiers will be added in
|
||||
* future versions of the platform.
|
||||
*
|
||||
* @jls 8.1.1 Class Modifiers
|
||||
* @jls 8.3.1 Field Modifiers
|
||||
* @jls 8.4.3 Method Modifiers
|
||||
* @jls 8.8.3 Constructor Modifiers
|
||||
* @jls 9.1.1 Interface Modifiers
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @since 1.6
|
||||
*/
|
||||
|
||||
public enum Modifier {
|
||||
|
||||
// Note java.lang.reflect.Modifier includes INTERFACE, but that's a VMism.
|
||||
|
||||
/** The modifier {@code public} */ PUBLIC,
|
||||
/** The modifier {@code protected} */ PROTECTED,
|
||||
/** The modifier {@code private} */ PRIVATE,
|
||||
/** The modifier {@code abstract} */ ABSTRACT,
|
||||
/**
|
||||
* The modifier {@code default}
|
||||
* @since 1.8
|
||||
*/
|
||||
DEFAULT,
|
||||
/** The modifier {@code static} */ STATIC,
|
||||
|
||||
/**
|
||||
* The modifier {@code sealed}
|
||||
* @since 17
|
||||
*/
|
||||
SEALED,
|
||||
|
||||
/**
|
||||
* The modifier {@code non-sealed}
|
||||
* @since 17
|
||||
*/
|
||||
NON_SEALED {
|
||||
public String toString() {
|
||||
return "non-sealed";
|
||||
}
|
||||
},
|
||||
/** The modifier {@code final} */ FINAL,
|
||||
/** The modifier {@code transient} */ TRANSIENT,
|
||||
/** The modifier {@code volatile} */ VOLATILE,
|
||||
/** The modifier {@code synchronized} */ SYNCHRONIZED,
|
||||
/** The modifier {@code native} */ NATIVE,
|
||||
/** The modifier {@code strictfp} */ STRICTFP;
|
||||
|
||||
/**
|
||||
* Returns this modifier's name as defined in <cite>The
|
||||
* Java Language Specification</cite>.
|
||||
* The modifier name is the {@linkplain #name() name of the enum
|
||||
* constant} in lowercase and with any underscores ("{@code _}")
|
||||
* replaced with hyphens ("{@code -}").
|
||||
* @return the modifier's name
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return name().toLowerCase(java.util.Locale.US);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,384 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model.element;
|
||||
|
||||
import java.util.List;
|
||||
import jdkx.lang.model.type.TypeMirror;
|
||||
|
||||
/**
|
||||
* Represents a module program element. Provides access to
|
||||
* information about the module, its directives, and its members.
|
||||
*
|
||||
* @see jdkx.lang.model.util.Elements#getModuleOf
|
||||
* @since 9
|
||||
* @jls 7.7 Module Declarations
|
||||
*/
|
||||
public interface ModuleElement extends Element, QualifiedNameable {
|
||||
/**
|
||||
* {@return a {@linkplain jdkx.lang.model.type.NoType pseudo-type}
|
||||
* for this module}
|
||||
*
|
||||
* @see jdkx.lang.model.type.NoType
|
||||
* @see jdkx.lang.model.type.TypeKind#MODULE
|
||||
*/
|
||||
@Override
|
||||
TypeMirror asType();
|
||||
|
||||
/**
|
||||
* Returns the fully qualified name of this module. For an
|
||||
* {@linkplain #isUnnamed() unnamed module}, an <a
|
||||
* href=Name.html#empty_name>empty name</a> is returned.
|
||||
*
|
||||
* @apiNote If the module name consists of one identifier, then
|
||||
* this method returns that identifier, which is deemed to be
|
||||
* module's fully qualified name despite not being in qualified
|
||||
* form. If the module name consists of more than one identifier,
|
||||
* then this method returns the entire name.
|
||||
*
|
||||
* @return the fully qualified name of this module, or an
|
||||
* empty name if this is an unnamed module
|
||||
*
|
||||
* @jls 6.2 Names and Identifiers
|
||||
*/
|
||||
@Override
|
||||
Name getQualifiedName();
|
||||
|
||||
/**
|
||||
* Returns the simple name of this module. For an {@linkplain
|
||||
* #isUnnamed() unnamed module}, an <a
|
||||
* href=Name.html#empty_name>empty name</a> is returned.
|
||||
*
|
||||
* @apiNote If the module name consists of one identifier, then
|
||||
* this method returns that identifier. If the module name
|
||||
* consists of more than one identifier, then this method returns
|
||||
* the rightmost such identifier, which is deemed to be the
|
||||
* module's simple name.
|
||||
*
|
||||
* @return the simple name of this module or an empty name if
|
||||
* this is an unnamed module
|
||||
*
|
||||
* @jls 6.2 Names and Identifiers
|
||||
*/
|
||||
@Override
|
||||
Name getSimpleName();
|
||||
|
||||
/**
|
||||
* {@return the packages within this module}
|
||||
*/
|
||||
@Override
|
||||
List<? extends Element> getEnclosedElements();
|
||||
|
||||
/**
|
||||
* {@return {@code true} if this is an open module and {@code
|
||||
* false} otherwise}
|
||||
*/
|
||||
boolean isOpen();
|
||||
|
||||
/**
|
||||
* {@return {@code true} if this is an unnamed module and {@code
|
||||
* false} otherwise}
|
||||
*
|
||||
* @jls 7.7.5 Unnamed Modules
|
||||
*/
|
||||
boolean isUnnamed();
|
||||
|
||||
/**
|
||||
* Returns {@code null} since a module is not enclosed by another
|
||||
* element.
|
||||
*
|
||||
* @return {@code null}
|
||||
*/
|
||||
@Override
|
||||
Element getEnclosingElement();
|
||||
|
||||
/**
|
||||
* Returns the directives contained in the declaration of this module.
|
||||
* @return the directives in the declaration of this module
|
||||
*/
|
||||
List<? extends Directive> getDirectives();
|
||||
|
||||
/**
|
||||
* The {@code kind} of a directive.
|
||||
*
|
||||
* <p>Note that it is possible additional directive kinds will be added
|
||||
* to accommodate new, currently unknown, language structures added to
|
||||
* future versions of the Java programming language.
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
enum DirectiveKind {
|
||||
/** A "requires (static|transitive)* module-name" directive. */
|
||||
REQUIRES,
|
||||
/** An "exports package-name [to module-name-list]" directive. */
|
||||
EXPORTS,
|
||||
/** An "opens package-name [to module-name-list]" directive. */
|
||||
OPENS,
|
||||
/** A "uses service-name" directive. */
|
||||
USES,
|
||||
/** A "provides service-name with implementation-name" directive. */
|
||||
PROVIDES
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a directive within the declaration of this
|
||||
* module. The directives of a module declaration configure the
|
||||
* module in the Java Platform Module System.
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
interface Directive {
|
||||
/**
|
||||
* {@return the {@code kind} of this directive}
|
||||
* <ul>
|
||||
*
|
||||
* <li> The kind of a {@linkplain RequiresDirective requires
|
||||
* directive} is {@link DirectiveKind#REQUIRES REQUIRES}.
|
||||
*
|
||||
* <li> The kind of an {@linkplain ExportsDirective exports
|
||||
* directive} is {@link DirectiveKind#EXPORTS EXPORTS}.
|
||||
*
|
||||
* <li> The kind of an {@linkplain OpensDirective opens
|
||||
* directive} is {@link DirectiveKind#OPENS OPENS}.
|
||||
*
|
||||
* <li> The kind of a {@linkplain UsesDirective uses
|
||||
* directive} is {@link DirectiveKind#USES USES}.
|
||||
*
|
||||
* <li> The kind of a {@linkplain ProvidesDirective provides
|
||||
* directive} is {@link DirectiveKind#PROVIDES PROVIDES}.
|
||||
*
|
||||
* </ul>
|
||||
*/
|
||||
DirectiveKind getKind();
|
||||
|
||||
/**
|
||||
* Applies a visitor to this directive.
|
||||
*
|
||||
* @param <R> the return type of the visitor's methods
|
||||
* @param <P> the type of the additional parameter to the visitor's methods
|
||||
* @param v the visitor operating on this directive
|
||||
* @param p additional parameter to the visitor
|
||||
* @return a visitor-specified result
|
||||
*/
|
||||
<R, P> R accept(DirectiveVisitor<R, P> v, P p);
|
||||
}
|
||||
|
||||
/**
|
||||
* A visitor of module directives, in the style of the visitor design
|
||||
* pattern. Classes implementing this interface are used to operate
|
||||
* on a directive when the kind of directive is unknown at compile time.
|
||||
* When a visitor is passed to a directive's {@link Directive#accept
|
||||
* accept} method, the <code>visit<i>Xyz</i></code> method applicable
|
||||
* to that directive is invoked.
|
||||
*
|
||||
* <p> Classes implementing this interface may or may not throw a
|
||||
* {@code NullPointerException} if the additional parameter {@code p}
|
||||
* is {@code null}; see documentation of the implementing class for
|
||||
* details.
|
||||
*
|
||||
* <p> <b>WARNING:</b> It is possible that methods will be added to
|
||||
* this interface to accommodate new, currently unknown, language
|
||||
* structures added to future versions of the Java programming
|
||||
* language. Methods to accommodate new language constructs will
|
||||
* be added in a source <em>compatible</em> way using
|
||||
* <em>default methods</em>.
|
||||
*
|
||||
* @param <R> the return type of this visitor's methods. Use {@link
|
||||
* Void} for visitors that do not need to return results.
|
||||
* @param <P> the type of the additional parameter to this visitor's
|
||||
* methods. Use {@code Void} for visitors that do not need an
|
||||
* additional parameter.
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
interface DirectiveVisitor<R, P> {
|
||||
/**
|
||||
* Visits any directive as if by passing itself to that
|
||||
* directive's {@link Directive#accept accept} method and passing
|
||||
* {@code null} for the additional parameter.
|
||||
*
|
||||
* @param d the directive to visit
|
||||
* @return a visitor-specified result
|
||||
* @implSpec The default implementation is {@code d.accept(v, null)}.
|
||||
*/
|
||||
default R visit(Directive d) {
|
||||
return d.accept(this, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits any directive as if by passing itself to that
|
||||
* directive's {@link Directive#accept accept} method.
|
||||
*
|
||||
* @param d the directive to visit
|
||||
* @param p a visitor-specified parameter
|
||||
* @return a visitor-specified result
|
||||
* @implSpec The default implementation is {@code d.accept(v, p)}.
|
||||
*/
|
||||
default R visit(Directive d, P p) {
|
||||
return d.accept(this, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a {@code requires} directive.
|
||||
* @param d the directive to visit
|
||||
* @param p a visitor-specified parameter
|
||||
* @return a visitor-specified result
|
||||
*/
|
||||
R visitRequires(RequiresDirective d, P p);
|
||||
|
||||
/**
|
||||
* Visits an {@code exports} directive.
|
||||
* @param d the directive to visit
|
||||
* @param p a visitor-specified parameter
|
||||
* @return a visitor-specified result
|
||||
*/
|
||||
R visitExports(ExportsDirective d, P p);
|
||||
|
||||
/**
|
||||
* Visits an {@code opens} directive.
|
||||
* @param d the directive to visit
|
||||
* @param p a visitor-specified parameter
|
||||
* @return a visitor-specified result
|
||||
*/
|
||||
R visitOpens(OpensDirective d, P p);
|
||||
|
||||
/**
|
||||
* Visits a {@code uses} directive.
|
||||
* @param d the directive to visit
|
||||
* @param p a visitor-specified parameter
|
||||
* @return a visitor-specified result
|
||||
*/
|
||||
R visitUses(UsesDirective d, P p);
|
||||
|
||||
/**
|
||||
* Visits a {@code provides} directive.
|
||||
* @param d the directive to visit
|
||||
* @param p a visitor-specified parameter
|
||||
* @return a visitor-specified result
|
||||
*/
|
||||
R visitProvides(ProvidesDirective d, P p);
|
||||
|
||||
/**
|
||||
* Visits an unknown directive.
|
||||
* This can occur if the language evolves and new kinds of directive are added.
|
||||
* @param d the directive to visit
|
||||
* @param p a visitor-specified parameter
|
||||
* @return a visitor-specified result
|
||||
* @throws UnknownDirectiveException a visitor implementation may optionally throw this exception
|
||||
* @implSpec The default implementation throws {@code new UnknownDirectiveException(d, p)}.
|
||||
*/
|
||||
default R visitUnknown(Directive d, P p) {
|
||||
throw new UnknownDirectiveException(d, p);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A dependency of a module.
|
||||
* @since 9
|
||||
*/
|
||||
interface RequiresDirective extends Directive {
|
||||
/**
|
||||
* {@return whether or not this is a static dependency}
|
||||
*/
|
||||
boolean isStatic();
|
||||
|
||||
/**
|
||||
* {@return whether or not this is a transitive dependency}
|
||||
*/
|
||||
boolean isTransitive();
|
||||
|
||||
/**
|
||||
* {@return the module that is required}
|
||||
*/
|
||||
ModuleElement getDependency();
|
||||
}
|
||||
|
||||
/**
|
||||
* An exported package of a module.
|
||||
* @since 9
|
||||
*/
|
||||
interface ExportsDirective extends Directive {
|
||||
|
||||
/**
|
||||
* {@return the package being exported}
|
||||
*/
|
||||
PackageElement getPackage();
|
||||
|
||||
/**
|
||||
* Returns the specific modules to which the package is being exported,
|
||||
* or {@code null}, if the package is exported to all modules which
|
||||
* have readability to this module.
|
||||
* @return the specific modules to which the package is being exported
|
||||
*/
|
||||
List<? extends ModuleElement> getTargetModules();
|
||||
}
|
||||
|
||||
/**
|
||||
* An opened package of a module.
|
||||
* @since 9
|
||||
*/
|
||||
interface OpensDirective extends Directive {
|
||||
|
||||
/**
|
||||
* {@return the package being opened}
|
||||
*/
|
||||
PackageElement getPackage();
|
||||
|
||||
/**
|
||||
* Returns the specific modules to which the package is being open
|
||||
* or {@code null}, if the package is open all modules which
|
||||
* have readability to this module.
|
||||
* @return the specific modules to which the package is being opened
|
||||
*/
|
||||
List<? extends ModuleElement> getTargetModules();
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of a service provided by a module.
|
||||
* @since 9
|
||||
*/
|
||||
interface ProvidesDirective extends Directive {
|
||||
/**
|
||||
* {@return the service being provided}
|
||||
*/
|
||||
TypeElement getService();
|
||||
|
||||
/**
|
||||
* {@return the implementations of the service being provided}
|
||||
*/
|
||||
List<? extends TypeElement> getImplementations();
|
||||
}
|
||||
|
||||
/**
|
||||
* A reference to a service used by a module.
|
||||
* @since 9
|
||||
*/
|
||||
interface UsesDirective extends Directive {
|
||||
/**
|
||||
* {@return the service that is used}
|
||||
*/
|
||||
TypeElement getService();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model.element;
|
||||
|
||||
/**
|
||||
* An immutable sequence of characters. When created by the same
|
||||
* implementation, objects implementing this interface must obey the
|
||||
* general {@linkplain Object#equals equals contract} when compared
|
||||
* with each other. Therefore, {@code Name} objects from the same
|
||||
* implementation are usable in collections while {@code Name}s from
|
||||
* different implementations may not work properly in collections.
|
||||
*
|
||||
* <p id="empty_name">An {@linkplain CharSequence#isEmpty() empty}
|
||||
* {@code Name} has a {@linkplain CharSequence#length() length} of
|
||||
* zero.
|
||||
*
|
||||
* <p>In the context of {@linkplain
|
||||
* jdkx.annotation.processing.ProcessingEnvironment annotation
|
||||
* processing}, the guarantees for "the same" implementation must
|
||||
* include contexts where the {@linkplain jdkx.annotation.processing
|
||||
* API mediated} side effects of {@linkplain
|
||||
* jdkx.annotation.processing.Processor processors} could be visible
|
||||
* to each other, including successive annotation processing
|
||||
* {@linkplain jdkx.annotation.processing.RoundEnvironment rounds}.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @see jdkx.lang.model.util.Elements#getName
|
||||
* @since 1.6
|
||||
*/
|
||||
public interface Name extends CharSequence {
|
||||
/**
|
||||
* Returns {@code true} if the argument represents the same
|
||||
* name as {@code this}, and {@code false} otherwise.
|
||||
*
|
||||
* <p>Note that the identity of a {@code Name} is a function both
|
||||
* of its content in terms of a sequence of characters as well as
|
||||
* the implementation which created it.
|
||||
*
|
||||
* @param obj the object to be compared with this element
|
||||
* @return {@code true} if the specified object represents the same
|
||||
* name as this
|
||||
* @see Element#equals
|
||||
*/
|
||||
boolean equals(Object obj);
|
||||
|
||||
/**
|
||||
* Obeys the general contract of {@link Object#hashCode Object.hashCode}.
|
||||
*
|
||||
* @see #equals
|
||||
*/
|
||||
int hashCode();
|
||||
|
||||
/**
|
||||
* Compares this name to the specified {@code CharSequence}. The result
|
||||
* is {@code true} if and only if this name represents the same sequence
|
||||
* of {@code char} values as the specified sequence.
|
||||
*
|
||||
* @return {@code true} if this name represents the same sequence
|
||||
* of {@code char} values as the specified sequence, {@code false}
|
||||
* otherwise
|
||||
*
|
||||
* @param cs The sequence to compare this name against
|
||||
* @see String#contentEquals(CharSequence)
|
||||
*/
|
||||
boolean contentEquals(CharSequence cs);
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model.element;
|
||||
|
||||
/**
|
||||
* The <i>nesting kind</i> of a type element.
|
||||
* Type elements come in four varieties:
|
||||
* top-level, member, local, and anonymous.
|
||||
* <i>Nesting kind</i> is a non-standard term used here to denote this
|
||||
* classification.
|
||||
*
|
||||
* <p>Note that it is possible additional nesting kinds will be added
|
||||
* in future versions of the platform.
|
||||
*
|
||||
* <p><b>Example:</b> The classes below are annotated with their nesting kind.
|
||||
* <blockquote><pre>
|
||||
*
|
||||
* import java.lang.annotation.*;
|
||||
* import static java.lang.annotation.RetentionPolicy.*;
|
||||
* import jdkx.lang.model.element.*;
|
||||
* import static jdkx.lang.model.element.NestingKind.*;
|
||||
*
|
||||
* @Nesting(TOP_LEVEL)
|
||||
* public class NestingExamples {
|
||||
* @Nesting(MEMBER)
|
||||
* static class MemberClass1{}
|
||||
*
|
||||
* @Nesting(MEMBER)
|
||||
* class MemberClass2{}
|
||||
*
|
||||
* public static void main(String... argv) {
|
||||
* @Nesting(LOCAL)
|
||||
* class LocalClass{};
|
||||
*
|
||||
* Class<?>[] classes = {
|
||||
* NestingExamples.class,
|
||||
* MemberClass1.class,
|
||||
* MemberClass2.class,
|
||||
* LocalClass.class
|
||||
* };
|
||||
*
|
||||
* for(Class<?> clazz : classes) {
|
||||
* System.out.format("%s is %s%n",
|
||||
* clazz.getName(),
|
||||
* clazz.getAnnotation(Nesting.class).value());
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @Retention(RUNTIME)
|
||||
* @interface Nesting {
|
||||
* NestingKind value();
|
||||
* }
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @since 1.6
|
||||
*/
|
||||
public enum NestingKind {
|
||||
/**
|
||||
* A top-level class or interface, not contained within another
|
||||
* class or interface.
|
||||
*/
|
||||
TOP_LEVEL,
|
||||
|
||||
/**
|
||||
* A class or interface that is a named member of another class or
|
||||
* interface.
|
||||
* @jls 8.5 Member Class and Interface Declarations
|
||||
*/
|
||||
MEMBER,
|
||||
|
||||
/**
|
||||
* A named class or interface declared within a construct other
|
||||
* than a class or interface.
|
||||
* @jls 14.3 Local Class Declarations
|
||||
*/
|
||||
LOCAL,
|
||||
|
||||
/**
|
||||
* A class without a name.
|
||||
* @jls 15.9.5 Anonymous Class Declarations
|
||||
*/
|
||||
ANONYMOUS;
|
||||
|
||||
/**
|
||||
* Does this constant correspond to a nested type element?
|
||||
* A <i>nested</i> type element is any that is not top-level.
|
||||
* More specifically, an <i>inner</i> type element is any nested type element that
|
||||
* is not {@linkplain Modifier#STATIC static}.
|
||||
* @return whether or not the constant is nested
|
||||
* @jls 14.3 Local Class Declarations
|
||||
*/
|
||||
public boolean isNested() {
|
||||
return this != TOP_LEVEL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model.element;
|
||||
|
||||
import java.util.List;
|
||||
import jdkx.lang.model.type.TypeMirror;
|
||||
|
||||
/**
|
||||
* Represents a package program element. Provides access to information
|
||||
* about the package and its members.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @see jdkx.lang.model.util.Elements#getPackageOf
|
||||
* @since 1.6
|
||||
*/
|
||||
public interface PackageElement extends Element, QualifiedNameable {
|
||||
/**
|
||||
* {@return a {@linkplain jdkx.lang.model.type.NoType pseudo-type}
|
||||
* for this package}
|
||||
*
|
||||
* @see jdkx.lang.model.type.NoType
|
||||
* @see jdkx.lang.model.type.TypeKind#PACKAGE
|
||||
*/
|
||||
@Override
|
||||
TypeMirror asType();
|
||||
|
||||
/**
|
||||
* Returns the fully qualified name of this package. This is also
|
||||
* known as the package's <i>canonical</i> name. For an
|
||||
* {@linkplain #isUnnamed() unnamed package}, an <a
|
||||
* href=Name.html#empty_name>empty name</a> is returned.
|
||||
*
|
||||
* @apiNote The fully qualified name of a named package that is
|
||||
* not a subpackage of a named package is its simple name. The
|
||||
* fully qualified name of a named package that is a subpackage of
|
||||
* another named package consists of the fully qualified name of
|
||||
* the containing package, followed by "{@code .}", followed by the simple
|
||||
* (member) name of the subpackage.
|
||||
*
|
||||
* @return the fully qualified name of this package, or an
|
||||
* empty name if this is an unnamed package
|
||||
* @jls 6.7 Fully Qualified Names and Canonical Names
|
||||
*/
|
||||
Name getQualifiedName();
|
||||
|
||||
/**
|
||||
* Returns the simple name of this package. For an {@linkplain
|
||||
* #isUnnamed() unnamed package}, an <a
|
||||
* href=Name.html#empty_name>empty name</a> is returned.
|
||||
*
|
||||
* @return the simple name of this package or an empty name if
|
||||
* this is an unnamed package
|
||||
*/
|
||||
@Override
|
||||
Name getSimpleName();
|
||||
|
||||
/**
|
||||
* {@return the {@linkplain NestingKind#TOP_LEVEL top-level}
|
||||
* classes and interfaces within this package} Note that
|
||||
* subpackages are <em>not</em> considered to be enclosed by a
|
||||
* package.
|
||||
*/
|
||||
@Override
|
||||
List<? extends Element> getEnclosedElements();
|
||||
|
||||
/**
|
||||
* {@return {@code true} if this is an unnamed package and {@code
|
||||
* false} otherwise}
|
||||
*
|
||||
* @jls 7.4.2 Unnamed Packages
|
||||
*/
|
||||
boolean isUnnamed();
|
||||
|
||||
/**
|
||||
* {@return the enclosing module if such a module exists; otherwise
|
||||
* {@code null}}
|
||||
*
|
||||
* One situation where a module does not exist for a package is if
|
||||
* the environment does not include modules, such as an annotation
|
||||
* processing environment configured for a {@linkplain
|
||||
* jdkx.annotation.processing.ProcessingEnvironment#getSourceVersion
|
||||
* source version} without modules.
|
||||
*
|
||||
* @revised 9
|
||||
*/
|
||||
@Override
|
||||
Element getEnclosingElement();
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model.element;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A mixin interface for an element that has type parameters.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @since 1.7
|
||||
*/
|
||||
public interface Parameterizable extends Element {
|
||||
/**
|
||||
* Returns the formal type parameters of an element in
|
||||
* declaration order.
|
||||
*
|
||||
* @return the formal type parameters, or an empty list
|
||||
* if there are none
|
||||
*/
|
||||
List<? extends TypeParameterElement> getTypeParameters();
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model.element;
|
||||
|
||||
/**
|
||||
* A mixin interface for an element that has a qualified name.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @since 1.7
|
||||
*/
|
||||
public interface QualifiedNameable extends Element {
|
||||
/**
|
||||
* {@return the fully qualified name of an element}
|
||||
*/
|
||||
Name getQualifiedName();
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model.element;
|
||||
|
||||
/**
|
||||
* Represents a record component.
|
||||
*
|
||||
* @since 16
|
||||
*/
|
||||
|
||||
public interface RecordComponentElement extends Element {
|
||||
/**
|
||||
* {@return the enclosing element of this record component}
|
||||
*
|
||||
* The enclosing element of a record component is the record class
|
||||
* declaring the record component.
|
||||
*/
|
||||
@Override
|
||||
Element getEnclosingElement();
|
||||
|
||||
/**
|
||||
* {@return the simple name of this record component}
|
||||
*
|
||||
* <p>The name of each record component must be distinct from the
|
||||
* names of all other record components of the same record.
|
||||
*
|
||||
* @jls 6.2 Names and Identifiers
|
||||
*/
|
||||
@Override
|
||||
Name getSimpleName();
|
||||
|
||||
/**
|
||||
* Returns the executable element for the accessor associated with the
|
||||
* given record component.
|
||||
*
|
||||
* @return the record component accessor.
|
||||
*/
|
||||
ExecutableElement getAccessor();
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model.element;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import jdkx.lang.model.type.*;
|
||||
import jdkx.lang.model.util.*;
|
||||
|
||||
/**
|
||||
* Represents a class or interface program element. Provides access
|
||||
* to information about the class or interface and its members. Note
|
||||
* that an enum class and a record class are specialized kinds of
|
||||
* classes and an annotation interface is a specialized kind of
|
||||
* interface.
|
||||
*
|
||||
* <p> While a {@code TypeElement} represents a class or interface
|
||||
* <i>element</i>, a {@link DeclaredType} represents a class
|
||||
* or interface <i>type</i>, the latter being a use
|
||||
* (or <i>invocation</i>) of the former.
|
||||
* The distinction is most apparent with generic types,
|
||||
* for which a single element can define a whole
|
||||
* family of types. For example, the element
|
||||
* {@code java.util.Set} corresponds to the parameterized types
|
||||
* {@code java.util.Set<String>} and {@code java.util.Set<Number>}
|
||||
* (and many others), and to the raw type {@code java.util.Set}.
|
||||
*
|
||||
* <p> Each method of this interface that returns a list of elements
|
||||
* will return them in the order that is natural for the underlying
|
||||
* source of program information. For example, if the underlying
|
||||
* source of information is Java source code, then the elements will be
|
||||
* returned in source code order.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @see DeclaredType
|
||||
* @since 1.6
|
||||
*/
|
||||
public interface TypeElement extends Element, Parameterizable, QualifiedNameable {
|
||||
/**
|
||||
* Returns the type defined by this class or interface element,
|
||||
* returning the <i>prototypical</i> type for an element
|
||||
* representing a generic type.
|
||||
*
|
||||
* <p>A generic element defines a family of types, not just one.
|
||||
* If this is a generic element, a prototypical type is
|
||||
* returned which has the element's invocation on the
|
||||
* type variables corresponding to its own formal type parameters.
|
||||
* For example,
|
||||
* for the generic class element {@code C<N extends Number>},
|
||||
* the parameterized type {@code C<N>} is returned.
|
||||
* The {@link Types} utility interface has more general methods
|
||||
* for obtaining the full range of types defined by an element.
|
||||
*
|
||||
* @return the type defined by this type element
|
||||
*
|
||||
* @see Types#asMemberOf(DeclaredType, Element)
|
||||
* @see Types#getDeclaredType(TypeElement, TypeMirror...)
|
||||
*/
|
||||
@Override
|
||||
TypeMirror asType();
|
||||
|
||||
/**
|
||||
* Returns the fields, methods, constructors, record components,
|
||||
* and member classes and interfaces that are directly declared in
|
||||
* this class or interface.
|
||||
*
|
||||
* This includes any {@linkplain Elements.Origin#MANDATED
|
||||
* mandated} elements such as the (implicit) default constructor
|
||||
* and the implicit {@code values} and {@code valueOf} methods of
|
||||
* an enum class.
|
||||
*
|
||||
* @apiNote As a particular instance of the {@linkplain
|
||||
* jdkx.lang.model.element general accuracy requirements} and the
|
||||
* ordering behavior required of this interface, the list of
|
||||
* enclosed elements will be returned in the natural order for the
|
||||
* originating source of information about the class or interface.
|
||||
* For example, if the information about the class or interface is
|
||||
* originating from a source file, the elements will be returned
|
||||
* in source code order. (However, in that case the ordering of
|
||||
* {@linkplain Elements.Origin#MANDATED implicitly declared}
|
||||
* elements, such as default constructors, is not specified.)
|
||||
*
|
||||
* @return the enclosed elements in proper order, or an empty list if none
|
||||
*
|
||||
* @jls 8.8.9 Default Constructor
|
||||
* @jls 8.9.3 Enum Members
|
||||
*/
|
||||
@Override
|
||||
List<? extends Element> getEnclosedElements();
|
||||
|
||||
/**
|
||||
* Returns the <i>nesting kind</i> of this class or interface element.
|
||||
*
|
||||
* @return the nesting kind of this class or interface element
|
||||
*/
|
||||
NestingKind getNestingKind();
|
||||
|
||||
/**
|
||||
* Returns the fully qualified name of this class or interface
|
||||
* element. More precisely, it returns the <i>canonical</i> name.
|
||||
* For local and anonymous classes, which do not have canonical
|
||||
* names, an <a href=Name.html#empty_name>empty name</a> is
|
||||
* returned.
|
||||
*
|
||||
* <p>The name of a generic class or interface does not include any reference
|
||||
* to its formal type parameters.
|
||||
* For example, the fully qualified name of the interface
|
||||
* {@code java.util.Set<E>} is "{@code java.util.Set}".
|
||||
* Nested classes and interfaces use "{@code .}" as a separator, as in
|
||||
* "{@code java.util.Map.Entry}".
|
||||
*
|
||||
* @return the fully qualified name of this class or interface, or
|
||||
* an empty name if none
|
||||
*
|
||||
* @see Elements#getBinaryName
|
||||
* @jls 6.7 Fully Qualified Names and Canonical Names
|
||||
*/
|
||||
Name getQualifiedName();
|
||||
|
||||
/**
|
||||
* Returns the simple name of this class or interface element.
|
||||
*
|
||||
* For an anonymous class, an <a href=Name.html#empty_name> empty
|
||||
* name</a> is returned.
|
||||
*
|
||||
* @return the simple name of this class or interface,
|
||||
* an empty name for an anonymous class
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
Name getSimpleName();
|
||||
|
||||
/**
|
||||
* Returns the direct superclass of this class or interface element.
|
||||
* If this class or interface element represents an interface or the class
|
||||
* {@code java.lang.Object}, then a {@link NoType}
|
||||
* with kind {@link TypeKind#NONE NONE} is returned.
|
||||
*
|
||||
* @return the direct superclass, or a {@code NoType} if there is none
|
||||
*/
|
||||
TypeMirror getSuperclass();
|
||||
|
||||
/**
|
||||
* Returns the interface types directly implemented by this class
|
||||
* or extended by this interface.
|
||||
*
|
||||
* @return the interface types directly implemented by this class
|
||||
* or extended by this interface, or an empty list if there are none
|
||||
*/
|
||||
List<? extends TypeMirror> getInterfaces();
|
||||
|
||||
/**
|
||||
* Returns the formal type parameters of this class or interface element
|
||||
* in declaration order.
|
||||
*
|
||||
* @return the formal type parameters, or an empty list
|
||||
* if there are none
|
||||
*/
|
||||
List<? extends TypeParameterElement> getTypeParameters();
|
||||
|
||||
/**
|
||||
* Returns the record components of this class or interface
|
||||
* element in declaration order.
|
||||
*
|
||||
* @implSpec The default implementations of this method returns an
|
||||
* empty and unmodifiable list.
|
||||
*
|
||||
* @return the record components, or an empty list if there are
|
||||
* none
|
||||
*
|
||||
* @since 16
|
||||
*/
|
||||
default List<? extends RecordComponentElement> getRecordComponents() {
|
||||
return Collections.unmodifiableList(Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the permitted classes of this class or interface
|
||||
* element in declaration order.
|
||||
*
|
||||
* @implSpec The default implementations of this method returns an
|
||||
* empty and unmodifiable list.
|
||||
*
|
||||
* @return the permitted classes, or an empty list if there are none
|
||||
*
|
||||
* @since 17
|
||||
*/
|
||||
default List<? extends TypeMirror> getPermittedSubclasses() {
|
||||
return Collections.unmodifiableList(new ArrayList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the package of a top-level class or interface and
|
||||
* returns the immediately lexically enclosing element for a
|
||||
* {@linkplain NestingKind#isNested nested} class or interface.
|
||||
*
|
||||
* @return the package of a top-level class or interface, the immediately
|
||||
* lexically enclosing element for a nested class or interface
|
||||
*/
|
||||
@Override
|
||||
Element getEnclosingElement();
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model.element;
|
||||
|
||||
import java.util.List;
|
||||
import jdkx.lang.model.type.TypeMirror;
|
||||
import jdkx.lang.model.type.TypeVariable;
|
||||
|
||||
/**
|
||||
* Represents a formal type parameter of a generic class, interface, method,
|
||||
* or constructor element.
|
||||
* A type parameter declares a {@link TypeVariable}.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @see TypeVariable
|
||||
* @since 1.6
|
||||
*/
|
||||
public interface TypeParameterElement extends Element {
|
||||
/**
|
||||
* {@return the {@linkplain TypeVariable type variable}
|
||||
* corresponding to this type parameter element}
|
||||
*
|
||||
* @see TypeVariable
|
||||
*/
|
||||
@Override
|
||||
TypeMirror asType();
|
||||
|
||||
/**
|
||||
* {@return the generic class, interface, method, or constructor that is
|
||||
* parameterized by this type parameter}
|
||||
*/
|
||||
Element getGenericElement();
|
||||
|
||||
/**
|
||||
* Returns the bounds of this type parameter.
|
||||
* These are the types given by the {@code extends} clause
|
||||
* used to declare this type parameter.
|
||||
* If no explicit {@code extends} clause was used,
|
||||
* then {@code java.lang.Object} is considered to be the sole bound.
|
||||
*
|
||||
* @return the bounds of this type parameter, or an empty list if
|
||||
* there are none
|
||||
*/
|
||||
List<? extends TypeMirror> getBounds();
|
||||
|
||||
/**
|
||||
* {@return the {@linkplain TypeParameterElement#getGenericElement
|
||||
* generic element} of this type parameter}
|
||||
*/
|
||||
@Override
|
||||
Element getEnclosingElement();
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model.element;
|
||||
|
||||
import jdkx.lang.model.UnknownEntityException;
|
||||
|
||||
/**
|
||||
* Indicates that an unknown kind of annotation value was encountered.
|
||||
* This can occur if the language evolves and new kinds of annotation
|
||||
* values can be stored in an annotation. May be thrown by an
|
||||
* {@linkplain AnnotationValueVisitor annotation value visitor} to
|
||||
* indicate that the visitor was created for a prior version of the
|
||||
* language.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @see AnnotationValueVisitor#visitUnknown
|
||||
* @since 1.6
|
||||
*/
|
||||
public class UnknownAnnotationValueException extends UnknownEntityException {
|
||||
|
||||
private static final long serialVersionUID = 269L;
|
||||
|
||||
private transient AnnotationValue av;
|
||||
private transient Object parameter;
|
||||
|
||||
/**
|
||||
* Creates a new {@code UnknownAnnotationValueException}. The
|
||||
* {@code p} parameter may be used to pass in an additional
|
||||
* argument with information about the context in which the
|
||||
* unknown annotation value was encountered; for example, the
|
||||
* visit methods of {@link AnnotationValueVisitor} may pass in
|
||||
* their additional parameter.
|
||||
*
|
||||
* @param av the unknown annotation value, may be {@code null}
|
||||
* @param p an additional parameter, may be {@code null}
|
||||
*/
|
||||
public UnknownAnnotationValueException(AnnotationValue av, Object p) {
|
||||
super("Unknown annotation value: \"" + av + "\"");
|
||||
this.av = av;
|
||||
this.parameter = p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unknown annotation value.
|
||||
* The value may be unavailable if this exception has been
|
||||
* serialized and then read back in.
|
||||
*
|
||||
* @return the unknown element, or {@code null} if unavailable
|
||||
*/
|
||||
public AnnotationValue getUnknownAnnotationValue() {
|
||||
return av;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the additional argument.
|
||||
*
|
||||
* @return the additional argument, or {@code null} if unavailable
|
||||
*/
|
||||
public Object getArgument() {
|
||||
return parameter;
|
||||
}
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model.element;
|
||||
|
||||
import jdkx.lang.model.UnknownEntityException;
|
||||
|
||||
/**
|
||||
* Indicates that an unknown kind of module directive was encountered.
|
||||
* This can occur if the language evolves and new kinds of directives are
|
||||
* added to the {@code Directive} hierarchy. May be thrown by a
|
||||
* {@linkplain ModuleElement.DirectiveVisitor directive visitor} to
|
||||
* indicate that the visitor was created for a prior version of the language.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @see ModuleElement.DirectiveVisitor#visitUnknown
|
||||
* @since 9
|
||||
*/
|
||||
public class UnknownDirectiveException extends UnknownEntityException {
|
||||
|
||||
private static final long serialVersionUID = 269L;
|
||||
|
||||
private final transient ModuleElement.Directive directive;
|
||||
private final transient Object parameter;
|
||||
|
||||
/**
|
||||
* Creates a new {@code UnknownElementException}. The {@code p}
|
||||
* parameter may be used to pass in an additional argument with
|
||||
* information about the context in which the unknown directive was
|
||||
* encountered; for example, the visit methods of {@link
|
||||
* ModuleElement.DirectiveVisitor DirectiveVisitor} may pass in
|
||||
* their additional parameter.
|
||||
*
|
||||
* @param d the unknown directive, may be {@code null}
|
||||
* @param p an additional parameter, may be {@code null}
|
||||
*/
|
||||
public UnknownDirectiveException(ModuleElement.Directive d, Object p) {
|
||||
super("Unknown directive: " + d);
|
||||
directive = d;
|
||||
parameter = p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unknown directive.
|
||||
* The value may be unavailable if this exception has been
|
||||
* serialized and then read back in.
|
||||
*
|
||||
* @return the unknown directive, or {@code null} if unavailable
|
||||
*/
|
||||
public ModuleElement.Directive getUnknownDirective() {
|
||||
return directive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the additional argument.
|
||||
*
|
||||
* @return the additional argument, or {@code null} if unavailable
|
||||
*/
|
||||
public Object getArgument() {
|
||||
return parameter;
|
||||
}
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model.element;
|
||||
|
||||
import jdkx.lang.model.UnknownEntityException;
|
||||
|
||||
/**
|
||||
* Indicates that an unknown kind of element was encountered. This
|
||||
* can occur if the language evolves and new kinds of elements are
|
||||
* added to the {@code Element} hierarchy. May be thrown by an
|
||||
* {@linkplain ElementVisitor element visitor} to indicate that the
|
||||
* visitor was created for a prior version of the language.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @see ElementVisitor#visitUnknown
|
||||
* @since 1.6
|
||||
*/
|
||||
public class UnknownElementException extends UnknownEntityException {
|
||||
|
||||
private static final long serialVersionUID = 269L;
|
||||
|
||||
private transient Element element;
|
||||
private transient Object parameter;
|
||||
|
||||
/**
|
||||
* Creates a new {@code UnknownElementException}. The {@code p}
|
||||
* parameter may be used to pass in an additional argument with
|
||||
* information about the context in which the unknown element was
|
||||
* encountered; for example, the visit methods of {@link
|
||||
* ElementVisitor} may pass in their additional parameter.
|
||||
*
|
||||
* @param e the unknown element, may be {@code null}
|
||||
* @param p an additional parameter, may be {@code null}
|
||||
*/
|
||||
public UnknownElementException(Element e, Object p) {
|
||||
super("Unknown element: \"" + e + "\"");
|
||||
element = e;
|
||||
this.parameter = p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unknown element.
|
||||
* The value may be unavailable if this exception has been
|
||||
* serialized and then read back in.
|
||||
*
|
||||
* @return the unknown element, or {@code null} if unavailable
|
||||
*/
|
||||
public Element getUnknownElement() {
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the additional argument.
|
||||
*
|
||||
* @return the additional argument, or {@code null} if unavailable
|
||||
*/
|
||||
public Object getArgument() {
|
||||
return parameter;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model.element;
|
||||
|
||||
import jdkx.lang.model.util.Elements;
|
||||
import jdkx.lang.model.type.TypeMirror;
|
||||
import jdkx.lang.model.type.TypeKind;
|
||||
|
||||
/**
|
||||
* Represents a field, {@code enum} constant, method or constructor
|
||||
* parameter, local variable, resource variable, or exception
|
||||
* parameter.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @since 1.6
|
||||
*/
|
||||
public interface VariableElement extends Element {
|
||||
/**
|
||||
* {@return the type of this variable}
|
||||
*
|
||||
* Note that the types of variables range over {@linkplain
|
||||
* TypeKind many kinds} of types, including primitive types,
|
||||
* declared types, and array types, among others.
|
||||
*
|
||||
* @see TypeKind
|
||||
*/
|
||||
@Override
|
||||
TypeMirror asType();
|
||||
|
||||
/**
|
||||
* Returns the value of this variable if this is a {@code final}
|
||||
* field initialized to a compile-time constant. Returns {@code
|
||||
* null} otherwise. The value will be of a primitive type or a
|
||||
* {@code String}. If the value is of a primitive type, it is
|
||||
* wrapped in the appropriate wrapper class (such as {@link
|
||||
* Integer}).
|
||||
*
|
||||
* <p>Note that not all {@code final} fields will have
|
||||
* constant values. In particular, {@code enum} constants are
|
||||
* <em>not</em> considered to be compile-time constants. To have a
|
||||
* constant value, a field's type must be either a primitive type
|
||||
* or {@code String}.
|
||||
*
|
||||
* @return the value of this variable if this is a {@code final}
|
||||
* field initialized to a compile-time constant, or {@code null}
|
||||
* otherwise
|
||||
*
|
||||
* @see Elements#getConstantExpression(Object)
|
||||
* @jls 15.29 Constant Expressions
|
||||
* @jls 4.12.4 final Variables
|
||||
*/
|
||||
Object getConstantValue();
|
||||
|
||||
/**
|
||||
* {@return the simple name of this variable element}
|
||||
*
|
||||
* <p>For method and constructor parameters, the name of each
|
||||
* parameter must be distinct from the names of all other
|
||||
* parameters of the same executable. If the original source
|
||||
* names are not available, an implementation may synthesize names
|
||||
* subject to the distinctness requirement above.
|
||||
*/
|
||||
@Override
|
||||
Name getSimpleName();
|
||||
|
||||
/**
|
||||
* {@return the enclosing element of this variable}
|
||||
*
|
||||
* The enclosing element of a method or constructor parameter is
|
||||
* the executable declaring the parameter.
|
||||
*/
|
||||
@Override
|
||||
Element getEnclosingElement();
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Interfaces used to model elements of the Java programming language.
|
||||
*
|
||||
* The term "element" in this package is used to refer to program
|
||||
* elements, the declared entities that make up a program. Elements
|
||||
* include classes, interfaces, methods, constructors, and fields.
|
||||
* The interfaces in this package do not model the structure of a
|
||||
* program inside a method body; for example there is no
|
||||
* representation of a {@code for} loop or {@code try}-{@code finally}
|
||||
* block. However, the interfaces can model some structures only
|
||||
* appearing inside method bodies, such as local variables and
|
||||
* anonymous classes.
|
||||
*
|
||||
* <p>When used in the context of annotation processing, an accurate
|
||||
* model of the element being represented must be returned. As this
|
||||
* is a language model, the source code provides the fiducial
|
||||
* (reference) representation of the construct in question rather than
|
||||
* a representation in an executable output like a class file.
|
||||
* Executable output may serve as the basis for creating a modeling
|
||||
* element. However, the process of translating source code to
|
||||
* executable output may not permit recovering some aspects of the
|
||||
* source code representation. For example, annotations with
|
||||
* {@linkplain java.lang.annotation.RetentionPolicy#SOURCE source}
|
||||
* {@linkplain java.lang.annotation.Retention retention} cannot be
|
||||
* recovered from class files and class files might not be able to
|
||||
* provide source position information.
|
||||
*
|
||||
* Names of {@linkplain
|
||||
* jdkx.lang.model.element.ExecutableElement#getParameters()
|
||||
* parameters} may not be recoverable from class files.
|
||||
*
|
||||
* The {@linkplain jdkx.lang.model.element.Modifier modifiers} on an
|
||||
* element created from a class file may differ in some cases from an
|
||||
* element for the same declaration created from a source file
|
||||
* including:
|
||||
*
|
||||
* <ul>
|
||||
* <li> {@code strictfp} on a class or interface
|
||||
* <li> {@code final} on a parameter
|
||||
* <li> {@code protected}, {@code private}, and {@code static} on classes and interfaces
|
||||
* </ul>
|
||||
*
|
||||
* Some elements which are {@linkplain
|
||||
* jdkx.lang.model.util.Elements.Origin#MANDATED mandated} may not be
|
||||
* marked as such when created from class files.
|
||||
*
|
||||
* Additionally, {@linkplain
|
||||
* jdkx.lang.model.util.Elements.Origin#SYNTHETIC synthetic}
|
||||
* constructs in a class file, such as accessor methods used in
|
||||
* implementing nested classes and {@linkplain
|
||||
* jdkx.lang.model.util.Elements.Origin#isBridge(ExecutableElement)
|
||||
* bridge methods} used in implementing covariant returns, are
|
||||
* translation artifacts strictly outside of this model. However, when
|
||||
* operating on class files, it is helpful be able to operate on such
|
||||
* elements, screening them out when appropriate.
|
||||
*
|
||||
* <p>During annotation processing, operating on incomplete or
|
||||
* erroneous programs is necessary; however, there are fewer
|
||||
* guarantees about the nature of the resulting model. If the source
|
||||
* code is not syntactically well-formed or has some other
|
||||
* irrecoverable error that could not be removed by the generation of
|
||||
* new classes or interfaces, a model may or may not be provided as a
|
||||
* quality of implementation issue. If a program is syntactically
|
||||
* valid but erroneous in some other fashion, any returned model must
|
||||
* have no less information than if all the method bodies in the
|
||||
* program were replaced by {@code "throw new RuntimeException();"}.
|
||||
* If a program refers to a missing class or interface Xyz, the
|
||||
* returned model must contain no less information than if the
|
||||
* declaration of class or interface Xyz were assumed to be {@code
|
||||
* "class Xyz {}"}, {@code "interface Xyz {}"}, {@code "enum Xyz {}"},
|
||||
* {@code "@interface Xyz {}"}, or {@code "record Xyz {}"}. If a
|
||||
* program refers to a missing class or interface {@code Xyz<K1,
|
||||
* ... ,Kn>}, the returned model must contain no less information than
|
||||
* if the declaration of Xyz were assumed to be {@code "class Xyz<T1,
|
||||
* ... ,Tn> {}"} or {@code "interface Xyz<T1, ... ,Tn> {}"}
|
||||
*
|
||||
* <p> Unless otherwise specified in a particular implementation, the
|
||||
* collections returned by methods in this package should be expected
|
||||
* to be unmodifiable by the caller and unsafe for concurrent access.
|
||||
*
|
||||
* <p> Unless otherwise specified, methods in this package will throw
|
||||
* a {@code NullPointerException} if given a {@code null} argument.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @see jdkx.lang.model.util.Elements
|
||||
* @jls 6.1 Declarations
|
||||
* @jls 7.4 Package Declarations
|
||||
* @jls 7.7 Module Declarations
|
||||
* @jls 8.1 Class Declarations
|
||||
* @jls 8.3 Field Declarations
|
||||
* @jls 8.4 Method Declarations
|
||||
* @jls 8.5 Member Class and Interface Declarations
|
||||
* @jls 8.8 Constructor Declarations
|
||||
* @jls 9.1 Interface Declarations
|
||||
* @since 1.6
|
||||
*/
|
||||
package jdkx.lang.model.element;
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Types and hierarchies of packages comprising a {@index "Java language
|
||||
* model"}, a model of the declarations and types of the Java
|
||||
* programming language.
|
||||
*
|
||||
* The members of this package and its subpackages are for use in
|
||||
* language modeling and language processing tasks and APIs including,
|
||||
* but not limited to, the {@linkplain jdkx.annotation.processing
|
||||
* annotation processing} framework.
|
||||
*
|
||||
* <p> This language model follows a <i>mirror</i>-based design; see
|
||||
*
|
||||
* <blockquote>
|
||||
* Gilad Bracha and David Ungar. <i>Mirrors: Design Principles for
|
||||
* Meta-level Facilities of Object-Oriented Programming Languages</i>.
|
||||
* In Proc. of the ACM Conf. on Object-Oriented Programming, Systems,
|
||||
* Languages and Applications, October 2004.
|
||||
* </blockquote>
|
||||
*
|
||||
* In particular, the model makes a distinction between declared
|
||||
* language constructs, like the {@linkplain jdkx.lang.model.element
|
||||
* element} representing {@code java.util.Set}, and the family of
|
||||
* {@linkplain jdkx.lang.model.type types} that may be associated
|
||||
* with an element, like the raw type {@code java.util.Set}, {@code
|
||||
* java.util.Set<String>}, and {@code java.util.Set<T>}.
|
||||
*
|
||||
* <p>Unless otherwise specified, methods in this package will throw
|
||||
* a {@code NullPointerException} if given a {@code null} argument.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @since 1.6
|
||||
*/
|
||||
|
||||
package jdkx.lang.model;
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model.type;
|
||||
|
||||
|
||||
/**
|
||||
* Represents an array type.
|
||||
* A multidimensional array type is represented as an array type
|
||||
* whose component type is also an array type.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @since 1.6
|
||||
*/
|
||||
public interface ArrayType extends ReferenceType {
|
||||
|
||||
/**
|
||||
* {@return the component type of this array type}
|
||||
*/
|
||||
TypeMirror getComponentType();
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model.type;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import jdkx.lang.model.element.Element;
|
||||
import jdkx.lang.model.element.TypeElement;
|
||||
import jdkx.lang.model.util.Types;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a declared type, either a class type or an interface type.
|
||||
* This includes parameterized types such as {@code java.util.Set<String>}
|
||||
* as well as raw types.
|
||||
*
|
||||
* <p> While a {@code TypeElement} represents a class or interface
|
||||
* <i>element</i>, a {@code DeclaredType} represents a class
|
||||
* or interface <i>type</i>, the latter being a use
|
||||
* (or <i>invocation</i>) of the former.
|
||||
* See {@link TypeElement} for more on this distinction.
|
||||
*
|
||||
* <p> The supertypes (both class and interface types) of a declared
|
||||
* type may be found using the {@link
|
||||
* Types#directSupertypes(TypeMirror)} method. This returns the
|
||||
* supertypes with any type arguments substituted in.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @see TypeElement
|
||||
* @since 1.6
|
||||
*/
|
||||
public interface DeclaredType extends ReferenceType {
|
||||
|
||||
/**
|
||||
* {@return the element corresponding to this type}
|
||||
*/
|
||||
Element asElement();
|
||||
|
||||
/**
|
||||
* Returns the type of the innermost enclosing instance or a
|
||||
* {@code NoType} of kind {@code NONE} if there is no enclosing
|
||||
* instance. Only types corresponding to inner classes have an
|
||||
* enclosing instance.
|
||||
*
|
||||
* @return a type mirror for the enclosing type
|
||||
* @jls 8.1.3 Inner Classes and Enclosing Instances
|
||||
* @jls 15.9.2 Determining Enclosing Instances
|
||||
*/
|
||||
TypeMirror getEnclosingType();
|
||||
|
||||
/**
|
||||
* Returns the actual type arguments of this type.
|
||||
* For a type nested within a parameterized type
|
||||
* (such as {@code Outer<String>.Inner<Number>}), only the type
|
||||
* arguments of the innermost type are included.
|
||||
*
|
||||
* @return the actual type arguments of this type, or an empty list
|
||||
* if none
|
||||
*/
|
||||
List<? extends TypeMirror> getTypeArguments();
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model.type;
|
||||
|
||||
/**
|
||||
* Represents a class or interface type that cannot be properly modeled.
|
||||
* This may be the result of a processing error,
|
||||
* such as a missing class file or erroneous source code.
|
||||
* Most queries for
|
||||
* information derived from such a type (such as its members or its
|
||||
* supertype) will not, in general, return meaningful results.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @since 1.6
|
||||
*/
|
||||
public interface ErrorType extends DeclaredType {
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model.type;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import jdkx.lang.model.element.ExecutableElement;
|
||||
|
||||
/**
|
||||
* Represents the type of an executable. An <i>executable</i>
|
||||
* is a method, constructor, or initializer.
|
||||
*
|
||||
* <p> The executable is
|
||||
* represented as when viewed as a method (or constructor or
|
||||
* initializer) of some reference type.
|
||||
* If that reference type is parameterized, then its actual
|
||||
* type arguments are substituted into any types returned by the methods of
|
||||
* this interface.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @see ExecutableElement
|
||||
* @since 1.6
|
||||
*/
|
||||
public interface ExecutableType extends TypeMirror {
|
||||
|
||||
/**
|
||||
* Returns the type variables declared by the formal type parameters
|
||||
* of this executable.
|
||||
*
|
||||
* @return the type variables declared by the formal type parameters,
|
||||
* or an empty list if there are none
|
||||
*/
|
||||
List<? extends TypeVariable> getTypeVariables();
|
||||
|
||||
/**
|
||||
* {@return the return type of this executable}
|
||||
* Returns a {@link NoType} with kind {@link TypeKind#VOID VOID}
|
||||
* if this executable is not a method, or is a method that does not
|
||||
* return a value.
|
||||
*/
|
||||
TypeMirror getReturnType();
|
||||
|
||||
/**
|
||||
* Returns the types of this executable's formal parameters.
|
||||
*
|
||||
* @return the types of this executable's formal parameters,
|
||||
* or an empty list if there are none
|
||||
*/
|
||||
List<? extends TypeMirror> getParameterTypes();
|
||||
|
||||
/**
|
||||
* Returns the receiver type of this executable,
|
||||
* or {@link jdkx.lang.model.type.NoType NoType} with
|
||||
* kind {@link jdkx.lang.model.type.TypeKind#NONE NONE}
|
||||
* if the executable has no receiver type.
|
||||
*
|
||||
* An executable which is an instance method, or a constructor of an
|
||||
* inner class, has a receiver type derived from the {@linkplain
|
||||
* ExecutableElement#getEnclosingElement declaring type}.
|
||||
*
|
||||
* An executable which is a static method, or a constructor of a
|
||||
* non-inner class, or an initializer (static or instance), has no
|
||||
* receiver type.
|
||||
*
|
||||
* @return the receiver type of this executable
|
||||
* @since 1.8
|
||||
*
|
||||
* @jls 8.4 Method Declarations
|
||||
* @jls 8.4.1 Formal Parameters
|
||||
* @jls 8.8 Constructor Declarations
|
||||
*/
|
||||
TypeMirror getReceiverType();
|
||||
|
||||
/**
|
||||
* Returns the exceptions and other throwables listed in this
|
||||
* executable's {@code throws} clause.
|
||||
*
|
||||
* @return the exceptions and other throwables listed in this
|
||||
* executable's {@code throws} clause,
|
||||
* or an empty list if there are none.
|
||||
*/
|
||||
List<? extends TypeMirror> getThrownTypes();
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model.type;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents an intersection type.
|
||||
*
|
||||
* <p>An intersection type can be either implicitly or explicitly
|
||||
* declared in a program. For example, the bound of the type parameter
|
||||
* {@code <T extends Number & Runnable>} is an (implicit) intersection
|
||||
* type. This is represented by an {@code IntersectionType} with
|
||||
* {@code Number} and {@code Runnable} as its bounds.
|
||||
*
|
||||
* @implNote In the reference implementation an {@code
|
||||
* IntersectionType} is used to model the explicit target type of a
|
||||
* cast expression.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public interface IntersectionType extends TypeMirror {
|
||||
|
||||
/**
|
||||
* {@return the bounds comprising this intersection type}
|
||||
*/
|
||||
List<? extends TypeMirror> getBounds();
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model.type;
|
||||
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.IOException;
|
||||
import jdkx.lang.model.element.Element;
|
||||
|
||||
|
||||
/**
|
||||
* Thrown when an application attempts to access the {@link Class} object
|
||||
* corresponding to a {@link TypeMirror}.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @see MirroredTypesException
|
||||
* @see Element#getAnnotation(Class)
|
||||
* @since 1.6
|
||||
*/
|
||||
public class MirroredTypeException extends MirroredTypesException {
|
||||
|
||||
private static final long serialVersionUID = 269;
|
||||
|
||||
private transient TypeMirror type; // cannot be serialized
|
||||
|
||||
/**
|
||||
* Constructs a new MirroredTypeException for the specified type.
|
||||
*
|
||||
* @param type the type being accessed
|
||||
*/
|
||||
public MirroredTypeException(TypeMirror type) {
|
||||
super("Attempt to access Class object for TypeMirror " + type.toString(), type);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type mirror corresponding to the type being accessed.
|
||||
* The type mirror may be unavailable if this exception has been
|
||||
* serialized and then read back in.
|
||||
*
|
||||
* @return the type mirror, or {@code null} if unavailable
|
||||
*/
|
||||
public TypeMirror getTypeMirror() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Explicitly set all transient fields.
|
||||
* @param s the serial stream
|
||||
* @throws ClassNotFoundException for a missing class during
|
||||
* deserialization
|
||||
* @throws IOException for an IO problem during deserialization
|
||||
*/
|
||||
private void readObject(ObjectInputStream s)
|
||||
throws IOException, ClassNotFoundException {
|
||||
s.defaultReadObject();
|
||||
type = null;
|
||||
types = null;
|
||||
}
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model.type;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Collections;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.IOException;
|
||||
import jdkx.lang.model.element.Element;
|
||||
|
||||
|
||||
/**
|
||||
* Thrown when an application attempts to access a sequence of {@link
|
||||
* Class} objects each corresponding to a {@link TypeMirror}.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @see MirroredTypeException
|
||||
* @see Element#getAnnotation(Class)
|
||||
* @since 1.6
|
||||
*/
|
||||
public class MirroredTypesException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 269;
|
||||
|
||||
transient List<? extends TypeMirror> types; // cannot be serialized
|
||||
|
||||
/*
|
||||
* Trusted constructor to be called by MirroredTypeException.
|
||||
*/
|
||||
MirroredTypesException(String message, TypeMirror type) {
|
||||
super(message);
|
||||
List<TypeMirror> tmp = (new ArrayList<>());
|
||||
tmp.add(type);
|
||||
types = Collections.unmodifiableList(tmp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new MirroredTypesException for the specified types.
|
||||
*
|
||||
* @param types the types being accessed
|
||||
*/
|
||||
public MirroredTypesException(List<? extends TypeMirror> types) {
|
||||
super("Attempt to access Class objects for TypeMirrors " +
|
||||
(types = // defensive copy
|
||||
new ArrayList<>(types)).toString() );
|
||||
this.types = Collections.unmodifiableList(types);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type mirrors corresponding to the types being accessed.
|
||||
* The type mirrors may be unavailable if this exception has been
|
||||
* serialized and then read back in.
|
||||
*
|
||||
* @return the type mirrors in construction order, or {@code null} if unavailable
|
||||
*/
|
||||
public List<? extends TypeMirror> getTypeMirrors() {
|
||||
return types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Explicitly set all transient fields.
|
||||
* @param s the serial stream
|
||||
* @throws ClassNotFoundException for a missing class during
|
||||
* deserialization
|
||||
* @throws IOException for an IO problem during deserialization
|
||||
*/
|
||||
private void readObject(ObjectInputStream s)
|
||||
throws IOException, ClassNotFoundException {
|
||||
s.defaultReadObject();
|
||||
types = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model.type;
|
||||
|
||||
import jdkx.lang.model.element.ExecutableElement;
|
||||
|
||||
|
||||
/**
|
||||
* A pseudo-type used where no actual type is appropriate.
|
||||
* The kinds of {@code NoType} are:
|
||||
* <ul>
|
||||
* <li>{@link TypeKind#VOID VOID} - corresponds to the keyword {@code void}.
|
||||
* <li>{@link TypeKind#PACKAGE PACKAGE} - the pseudo-type of a package element.
|
||||
* <li>{@link TypeKind#MODULE MODULE} - the pseudo-type of a module element.
|
||||
* <li>{@link TypeKind#NONE NONE} - used in other cases
|
||||
* where no actual type is appropriate; for example, the superclass
|
||||
* of {@code java.lang.Object}.
|
||||
* </ul>
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @see ExecutableElement#getReturnType()
|
||||
* @since 1.6
|
||||
*/
|
||||
|
||||
public interface NoType extends TypeMirror {
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model.type;
|
||||
|
||||
|
||||
/**
|
||||
* Represents the null type.
|
||||
* This is the type of the expression {@code null},
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @jls 3.10.7 The Null Literal
|
||||
* @jls 4.1 The Kinds of Types and Values
|
||||
* @since 1.6
|
||||
*/
|
||||
|
||||
public interface NullType extends ReferenceType {
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdkx.lang.model.type;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a primitive type. These include
|
||||
* {@code boolean}, {@code byte}, {@code short}, {@code int},
|
||||
* {@code long}, {@code char}, {@code float}, and {@code double}.
|
||||
*
|
||||
* @author Joseph D. Darcy
|
||||
* @author Scott Seligman
|
||||
* @author Peter von der Ahé
|
||||
* @jls 4.2 Primitive Types and Values
|
||||
* @since 1.6
|
||||
*/
|
||||
public interface PrimitiveType extends TypeMirror {
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user