FULL PRODUCT VERSION :
java version "1.7.0_03"
Java(TM) SE Runtime Environment (build 1.7.0_03-b04)
Java HotSpot(TM) Server VM (build 22.1-b02, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Ubuntu 11.04 linux
A DESCRIPTION OF THE PROBLEM :
We are using the tools/compiler API (javax.tools.*). The Diagnostic interface (javax.tools.Diagnostic) documentation for the 'getEndPosition()' method specifies that the method -
Returns:
offset from beginning of file; NOPOS if and only if getPosition() returns NOPOS
- yet we have found an error for which this is not true. Occurs when an implicit superclass constructor call doesn't match the signature of the superclass constructor. See test case below.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Write code which uses the javax.tools.* API
2. Use it to compile code with an implicit constructor call to a non-existing superclass constructor (see test case for example)
3. Check the 'Diagnostic' object that is returned
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
(getStartPosition() == NOPOS || getEndPosition() != NOPOS), as per documentation
ACTUAL -
(getStartPosition() != NOPOS && getEndPosition() == NOPOS) instead.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
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.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.NestingKind;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticListener;
import javax.tools.FileObject;
import javax.tools.ForwardingJavaFileManager;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.JavaFileObject.Kind;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
import com.sun.xml.internal.messaging.saaj.util.ByteInputStream;
public class TestCAPI
{
public static void main(String [] args) throws Exception
{
final Diagnostic<? extends JavaFileObject>[] diags = new Diagnostic[1];
JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
DiagnosticListener<JavaFileObject> diagListener = new DiagnosticListener<JavaFileObject>() {
@Override
public void report(Diagnostic<? extends JavaFileObject> diag)
{
//System.out.println("Got diag: " + diag);
//System.out.println(" Start pos: " + diag.getStartPosition());
//System.out.println(" End pos: " + diag.getEndPosition());
diags[0] = diag;
}
};
List<String> optionsList = new LinkedList<String>();
final String egSrc = "class One { public One(int nn) { } }\n" +
"class Two extends One { public Two() { } }\n";
final byte[] srcBuf = egSrc.getBytes();
List<JavaFileObject> sources = new LinkedList<JavaFileObject>();
URI egFileUri = new URI("test://Two.java");
SimpleJavaFileObject srcObject= new SimpleJavaFileObject(egFileUri, Kind.SOURCE) {
@Override
public InputStream openInputStream() throws IOException
{
return new ByteInputStream(srcBuf, srcBuf.length);
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors)
throws IOException
{
return egSrc;
}
@Override
public Reader openReader(boolean ignoreEncodingErrors)
throws IOException
{
throw new NotImplementedException();
}
};
sources.add(srcObject);
StandardJavaFileManager sjfm = jc.getStandardFileManager(diagListener, null, null);
JavaFileManager jfm = new ForwardingJavaFileManager<StandardJavaFileManager>(sjfm) {
@Override
public void close() throws IOException
{
throw new NotImplementedException();
}
@Override
public void flush() throws IOException
{
}
@Override
public FileObject getFileForInput(Location location,
String packageName, String relativeName) throws IOException
{
throw new NotImplementedException();
}
@Override
public FileObject getFileForOutput(Location location,
String packageName, String relativeName, FileObject sibling)
throws IOException
{
throw new NotImplementedException();
}
@Override
public JavaFileObject getJavaFileForInput(Location location,
String className, Kind kind) throws IOException
{
throw new NotImplementedException();
}
@Override
public JavaFileObject getJavaFileForOutput(Location location,
String className, Kind kind, FileObject sibling)
throws IOException
{
return new JavaFileObject() {
@Override
public boolean delete()
{
return true;
}
@Override
public Modifier getAccessLevel()
{
return null;
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException
{
throw new NotImplementedException();
}
@Override
public Kind getKind()
{
throw new NotImplementedException();
}
@Override
public long getLastModified()
{
throw new NotImplementedException();
}
@Override
public String getName()
{
throw new NotImplementedException();
}
@Override
public NestingKind getNestingKind()
{
return null;
}
@Override
public boolean isNameCompatible(String simpleName, Kind kind)
{
throw new NotImplementedException();
}
@Override
public InputStream openInputStream() throws IOException
{
throw new NotImplementedException();
}
@Override
public OutputStream openOutputStream() throws IOException
{
return new OutputStream() {
@Override
public void write(int b) throws IOException
{
}
@Override
public void write(byte[] b) throws IOException
{
}
@Override
public void write(byte[] b, int off, int len)
throws IOException
{
}
};
}
@Override
public Reader openReader(boolean ignoreEncodingErrors)
throws IOException
{
throw new NotImplementedException();
}
@Override
public Writer openWriter() throws IOException
{
throw new NotImplementedException();
}
@Override
public URI toUri()
{
throw new NotImplementedException();
}
};
}
@Override
public boolean handleOption(String current,
Iterator<String> remaining)
{
throw new NotImplementedException();
}
@Override
public String inferBinaryName(Location location, JavaFileObject file)
{
return super.inferBinaryName(location, file);
}
@Override
public boolean isSameFile(FileObject a, FileObject b)
{
throw new NotImplementedException();
}
@Override
public int isSupportedOption(String arg0)
{
throw new NotImplementedException();
}
@Override
public Iterable<JavaFileObject> list(Location location,
String packageName, Set<Kind> kinds, boolean recurse)
throws IOException
{
return super.list(location, packageName, kinds, recurse);
}
};
jc.getTask(null, jfm, diagListener, optionsList, null, sources).call();
if (diags[0].getStartPosition() != Diagnostic.NOPOS
&& diags[0].getEndPosition() == Diagnostic.NOPOS)
{
System.err.println("Error - start position is set but end position is NOPOS");
System.exit(1);
}
System.exit(0);
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Check for condition getEndPosition() == NOPOS and use getStartPosition() as an approximation in that case.
java version "1.7.0_03"
Java(TM) SE Runtime Environment (build 1.7.0_03-b04)
Java HotSpot(TM) Server VM (build 22.1-b02, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Ubuntu 11.04 linux
A DESCRIPTION OF THE PROBLEM :
We are using the tools/compiler API (javax.tools.*). The Diagnostic interface (javax.tools.Diagnostic) documentation for the 'getEndPosition()' method specifies that the method -
Returns:
offset from beginning of file; NOPOS if and only if getPosition() returns NOPOS
- yet we have found an error for which this is not true. Occurs when an implicit superclass constructor call doesn't match the signature of the superclass constructor. See test case below.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Write code which uses the javax.tools.* API
2. Use it to compile code with an implicit constructor call to a non-existing superclass constructor (see test case for example)
3. Check the 'Diagnostic' object that is returned
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
(getStartPosition() == NOPOS || getEndPosition() != NOPOS), as per documentation
ACTUAL -
(getStartPosition() != NOPOS && getEndPosition() == NOPOS) instead.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
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.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.NestingKind;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticListener;
import javax.tools.FileObject;
import javax.tools.ForwardingJavaFileManager;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.JavaFileObject.Kind;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
import com.sun.xml.internal.messaging.saaj.util.ByteInputStream;
public class TestCAPI
{
public static void main(String [] args) throws Exception
{
final Diagnostic<? extends JavaFileObject>[] diags = new Diagnostic[1];
JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
DiagnosticListener<JavaFileObject> diagListener = new DiagnosticListener<JavaFileObject>() {
@Override
public void report(Diagnostic<? extends JavaFileObject> diag)
{
//System.out.println("Got diag: " + diag);
//System.out.println(" Start pos: " + diag.getStartPosition());
//System.out.println(" End pos: " + diag.getEndPosition());
diags[0] = diag;
}
};
List<String> optionsList = new LinkedList<String>();
final String egSrc = "class One { public One(int nn) { } }\n" +
"class Two extends One { public Two() { } }\n";
final byte[] srcBuf = egSrc.getBytes();
List<JavaFileObject> sources = new LinkedList<JavaFileObject>();
URI egFileUri = new URI("test://Two.java");
SimpleJavaFileObject srcObject= new SimpleJavaFileObject(egFileUri, Kind.SOURCE) {
@Override
public InputStream openInputStream() throws IOException
{
return new ByteInputStream(srcBuf, srcBuf.length);
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors)
throws IOException
{
return egSrc;
}
@Override
public Reader openReader(boolean ignoreEncodingErrors)
throws IOException
{
throw new NotImplementedException();
}
};
sources.add(srcObject);
StandardJavaFileManager sjfm = jc.getStandardFileManager(diagListener, null, null);
JavaFileManager jfm = new ForwardingJavaFileManager<StandardJavaFileManager>(sjfm) {
@Override
public void close() throws IOException
{
throw new NotImplementedException();
}
@Override
public void flush() throws IOException
{
}
@Override
public FileObject getFileForInput(Location location,
String packageName, String relativeName) throws IOException
{
throw new NotImplementedException();
}
@Override
public FileObject getFileForOutput(Location location,
String packageName, String relativeName, FileObject sibling)
throws IOException
{
throw new NotImplementedException();
}
@Override
public JavaFileObject getJavaFileForInput(Location location,
String className, Kind kind) throws IOException
{
throw new NotImplementedException();
}
@Override
public JavaFileObject getJavaFileForOutput(Location location,
String className, Kind kind, FileObject sibling)
throws IOException
{
return new JavaFileObject() {
@Override
public boolean delete()
{
return true;
}
@Override
public Modifier getAccessLevel()
{
return null;
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException
{
throw new NotImplementedException();
}
@Override
public Kind getKind()
{
throw new NotImplementedException();
}
@Override
public long getLastModified()
{
throw new NotImplementedException();
}
@Override
public String getName()
{
throw new NotImplementedException();
}
@Override
public NestingKind getNestingKind()
{
return null;
}
@Override
public boolean isNameCompatible(String simpleName, Kind kind)
{
throw new NotImplementedException();
}
@Override
public InputStream openInputStream() throws IOException
{
throw new NotImplementedException();
}
@Override
public OutputStream openOutputStream() throws IOException
{
return new OutputStream() {
@Override
public void write(int b) throws IOException
{
}
@Override
public void write(byte[] b) throws IOException
{
}
@Override
public void write(byte[] b, int off, int len)
throws IOException
{
}
};
}
@Override
public Reader openReader(boolean ignoreEncodingErrors)
throws IOException
{
throw new NotImplementedException();
}
@Override
public Writer openWriter() throws IOException
{
throw new NotImplementedException();
}
@Override
public URI toUri()
{
throw new NotImplementedException();
}
};
}
@Override
public boolean handleOption(String current,
Iterator<String> remaining)
{
throw new NotImplementedException();
}
@Override
public String inferBinaryName(Location location, JavaFileObject file)
{
return super.inferBinaryName(location, file);
}
@Override
public boolean isSameFile(FileObject a, FileObject b)
{
throw new NotImplementedException();
}
@Override
public int isSupportedOption(String arg0)
{
throw new NotImplementedException();
}
@Override
public Iterable<JavaFileObject> list(Location location,
String packageName, Set<Kind> kinds, boolean recurse)
throws IOException
{
return super.list(location, packageName, kinds, recurse);
}
};
jc.getTask(null, jfm, diagListener, optionsList, null, sources).call();
if (diags[0].getStartPosition() != Diagnostic.NOPOS
&& diags[0].getEndPosition() == Diagnostic.NOPOS)
{
System.err.println("Error - start position is set but end position is NOPOS");
System.exit(1);
}
System.exit(0);
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Check for condition getEndPosition() == NOPOS and use getStartPosition() as an approximation in that case.
- relates to
-
JDK-7157671 compiler tree API: incorrectly detects start/end positions under JDK6
-
- Closed
-