org.eclipse.jdt.internal.compiler.tool.PathFileObject Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (c) 2023 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.tool;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.NestingKind;
import javax.tools.JavaFileObject;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
import org.eclipse.jdt.internal.compiler.util.JRTUtil;
/**
* Implementation of a Java file object that corresponds to a file on the file system
*/
public class PathFileObject implements JavaFileObject {
Path path;
private final Charset charset;
private final Kind kind;
public PathFileObject(Path path, Kind kind, Charset charset) {
this.path = path;
this.kind = kind;
this.charset = charset;
}
/* (non-Javadoc)
* @see javax.tools.JavaFileObject#getAccessLevel()
*/
@Override
public Modifier getAccessLevel() {
// cannot express multiple modifier
if (getKind() != Kind.CLASS) {
return null;
}
ClassFileReader reader = null;
try {
reader = readFromPath(this.path);
} catch (ClassFormatException e) {
// ignore
} catch (IOException e) {
String error = "Failed to read access level from " + this.path; //$NON-NLS-1$
if (JRTUtil.PROPAGATE_IO_ERRORS) {
throw new IllegalStateException(error, e);
} else {
System.err.println(error);
e.printStackTrace();
}
}
if (reader == null) {
return null;
}
final int accessFlags = reader.accessFlags();
if ((accessFlags & ClassFileConstants.AccPublic) != 0) {
return Modifier.PUBLIC;
}
if ((accessFlags & ClassFileConstants.AccAbstract) != 0) {
return Modifier.ABSTRACT;
}
if ((accessFlags & ClassFileConstants.AccFinal) != 0) {
return Modifier.FINAL;
}
return null;
}
private ClassFileReader readFromPath(Path p) throws ClassFormatException, IOException {
return new ClassFileReader(this.path.toUri(), Files.readAllBytes(this.path), this.path.getFileName().toString().toCharArray());
}
/* (non-Javadoc)
* @see javax.tools.JavaFileObject#getNestingKind()
*/
@Override
public NestingKind getNestingKind() {
switch(this.kind) {
case SOURCE :
return NestingKind.TOP_LEVEL;
case CLASS :
ClassFileReader reader = null;
try {
reader = readFromPath(this.path);
} catch (ClassFormatException e) {
// ignore
} catch (IOException e) {
String error = "Failed to read access nesting kind from " + this.path; //$NON-NLS-1$
if (JRTUtil.PROPAGATE_IO_ERRORS) {
throw new IllegalStateException(error, e);
} else {
System.err.println(error);
e.printStackTrace();
}
}
if (reader == null) {
return null;
}
if (reader.isAnonymous()) {
return NestingKind.ANONYMOUS;
}
if (reader.isLocal()) {
return NestingKind.LOCAL;
}
if (reader.isMember()) {
return NestingKind.MEMBER;
}
return NestingKind.TOP_LEVEL;
default:
return null;
}
}
/**
* @see javax.tools.FileObject#delete()
*/
@Override
public boolean delete() {
return false;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof PathFileObject)) {
return false;
}
PathFileObject PathFileObject = (PathFileObject) o;
return PathFileObject.toUri().equals(this.path.toUri());
}
/**
* @see javax.tools.FileObject#getCharContent(boolean)
*/
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
return Util.getCharContents(this, ignoreEncodingErrors,
org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(this.path.toFile()), this.charset.name());
}
/**
* @see javax.tools.FileObject#getLastModified()
*/
@Override
public long getLastModified() {
return this.path.toFile().lastModified();
}
@Override
public String getName() {
return this.path.toString();
}
@Override
public int hashCode() {
return this.path.hashCode();
}
/**
* @see javax.tools.FileObject#openInputStream()
*/
@Override
public InputStream openInputStream() throws IOException {
return Files.newInputStream(this.path);
}
/**
* @see javax.tools.FileObject#openOutputStream()
*/
@Override
public OutputStream openOutputStream() throws IOException {
return Files.newOutputStream(this.path);
}
/**
* @see javax.tools.FileObject#openReader(boolean)
*/
@Override
public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
return Files.newBufferedReader(this.path);
}
/**
* @see javax.tools.FileObject#openWriter()
*/
@Override
public Writer openWriter() throws IOException {
return Files.newBufferedWriter(this.path);
}
@Override
public String toString() {
return this.path.toString();
}
@Override
public URI toUri() {
return this.path.toUri();
}
@Override
public Kind getKind() {
return this.kind;
}
@Override
public boolean isNameCompatible(String simpleName, Kind k) {
String fileName = this.path.getFileName().toString();
return fileName.endsWith(simpleName + k.extension);
}
}