My code:
FileChooser prompt = new FileChooser();
prompt.setTitle("Odaberi fajl");
source = (Source) prompt.showOpenDialog(new Stage());
where source is a class that extends File as such:
import java.io.File;
public class Source extends File {
public Source(String pathname) {
super(pathname);
}
}
returns an error when trying to cast to Source. I have no idea what is causing this.
FileChooser returns a File. What makes you think you can cast it to Source? It is not a Source.
What you want to do is one of:
Make Source encasulate a File and provide whatever custom methods you need, delegating to the contained File as appropriate.
public class Source {
private File f;
public Source(File f) {
this.f = f;
}
// Custom methods
...
// Delegating methods
public boolean exists() {
return f.exists();
}
...
}
Extend File as you are doing, but provide a constructor that takes another File (i.e. a copy constructor) and instantiates the Source using the data from the passed File.
public class Source extends File {
public Source(File f) {
super(f.getAbsolutePath());
}
// Custom methods
...
}
Then instantiate as follows:
FileChooser prompt = new FileChooser();
prompt.setTitle("Odaberi fajl");
source = new Source(prompt.showOpenDialog(new Stage()));
You need to understand what casting does.
Casting is a compile-time directive; it tells the compiler that the operation being performed (showOpenDialog() in your case) is going to return an object that matches the cast. If that turns out not to be true, then the program will throw an IllegalCastException at runtime. It is up to the programmer who writes the cast to ensure that the cast is going to be correct at runtime. The compiler will tell you if there is no possible way for it to be correct, in many cases, but cannot tell you in all cases.
FileChooser was written without knowledge of your Source class, so it is not possible for it to return a Source object. If the cast had succeeded, you would be allowed (by the compiler) to call methods from Source on the resulting object, and that would clearly be incorrect.
One thing to realize about casting is that, except in very limited circumstances involving boxed primitives, casting does not change the object referred to at all. Its purpose is to let the compiler know that operations will be legal on the resulting class.
As an aside, it helps enormously when asking a question to say what happens, not just 'returns an Error'. Is that a compile or runtime error? What does the error say? Please remember that for questions you ask in the future.
Related
Consider the following two lines of code:
final List<Path> paths = new ArrayList<>();
final FileVisitor<Path> fv = new SimpleFileVisitor<>();
To me, they look quite similar. However, the second line is refused by the Java compiler (1.8) with the message "Cannot infer type arguments for SimpleFileVisitor<>".
Can anyone please explain, what's the problem?
I don't see how you may get the error message Cannot infer type arguments because your syntax is correct, except for the fact that as many have said already, the class java.nio.file.SimpleFileVisitor has only one constructor which is protected:
protected SimpleFileVisitor() {
}
This means that only children of this class can initialize an instance of SimpleFileVisitor, and that's why your code doesn't compile.
I don't know this class, but by a quick look at the code I guess they simply expect you to extend it first (or use an already existing extension coming from somewhere else), and then use it the implementations of the FileVisitor interface.
If you don't have a concrete child class to use and want to create your own MySimpleFileVisitor:
public class MySimpleFileVisitor<T> extends SimpleFileVisitor<T> {
public MySimpleFileVisitor() {
super(); //<-- here you have the right to call the protected constructor of SimpleFileVisitor
}
}
... you will then be able to instantiate your class and use the already implemented methods like this:
FileVisitor<Path> fv = new MySimpleFileVisitor<>(); //<-- here you will be able to correctly infer parameter type as you do in your List example
fv.visitFile(file, attrs); //<-- here you enter the method implemented inside SimpleFileVisitor
I'm trying to use the Java TreePathScanner API to determine the list of class files that will be generated from a given compilation. For example, the following source code:
public class InnerClass {
private final InnerInnerClass clazz = new InnerInnerClass();
private class InnerInnerClass {
}
}
will generate the following files:
InnerClass.class
InnerClass$1.class
InnerClass$InnerInnerClass.class
However, in my TreePathScanner subclass, visitClass is only called twice, for the InnerClass class, and the InnerInnerClass classes, but not the anonymously named class created from the new class statement. Changing the source to the following works as expected:
public class InnerClass {
private final InnerInnerClass clazz = new InnerInnerClass() { };
private class InnerInnerClass {
}
}
My tool's full source code is available here for reference, specifically ArtifactScanner.java.
Either this is a bug or a flaw in the API as there doesn't seem to be any other way to get all of the binary names that will be generated from a given compilation unit's source code. Am I missing something?
One of the JDK developers explained on this bug report that the observed behavior really is not a bug, and that the additional class files are generated as a result of the Java compiler backend which rewrites more complex language constructs into simpler ones before generating class files.
The TreePathScanner API therefore does produce the correct output in this case, and the short of it is that TreePathScanner is the wrong solution to use for my use case (determining the list of class files that will be produced) and that com.sun.source.util.TaskListener, TaskEvent, and TaskEvent.Kind, and JavaFileManager.inferBinaryName should be used instead.
Not sure if I am wording this correctly. Please let me know if you require more information.
We have a requirement where we need to determine the type of variable based on a system environment variable.
So, say we have a the following class
class Test
{
DUMMY_TYPE testVariable;
}
The DUMMY_TYPE is determined based on a system variable. So when Java compiles, is it possible to have Java use the System Environment variable to determine the type at compile type?
Also, is it possible to set this up somehow on Eclipse, where Eclipse will continue to show me DUMMY_TYPE on the IDE wherever I use it, but when compiling and building it can substitute DUMMY_TYPE with the correct type based on environment variable?
I have an idea.
Make the testVariable of type Object (or a DummyType class which extends Object). Then you can load the variable with whatever data you want using the primitive wrapper classes, based on what you read from your system variable.
So:
public class Test {
Object testVariable;
{
String whichType = null;
//Logic to read your system variable from wherever and store it in whichType
if(whichType.equals("int")) {
testVariable = new Integer(intVal);
}
else if(whichType.equals("double")) {
testVariable = new Double(doubleVal);
}
//etc.
}
Of course, this isn't Java "figuring out" which type it is at compile time like you want, necessarily (and the assignment would take place at run time, when the Test object was created), but it seems like reasonable framework for an alternative.
And you can also set the value of the testVariable upon initialization as appropriate, naturally.
Alternatively, you could have a method like this which accepts inputs as a String (read from your system variable) and returns it in the appropriate wrapper class of the primitive type:
public Object getPrimitiveValue(String type, String value) {
if(type.equals("int")) {
return new Integer(Integer.parseInt(value));
}
else if(type.equals("double")) {
return new Double(Double.parseDouble(value));
}
//etc.
}
For reuse reasons I have wrapped my current serialization/deserialization services in an abstract generic class, which is compiled in a shared JAR across the project. I need to serialize objects to String
The class can be extended and a type can be specified for it in other JARs/WARs (yea, this is a web application).
When I made my first deserialization tests from within the same WAR it all worked fine, but now that I moved the abstract class into another JAR I get a ClassNotFoundError when deserializing.
The base class is structured as follows:
public abstract class ConverterBase<T extends Serializable> {
public final Object getAsObject(String str) {
//Use java.io serialization services from the base64 representation
try {
ByteArrayInputStream ba = new ByteArrayInputStream(decoder
.decodeBuffer(str));
try {
ObjectInputStream is = new ObjectInputStream(ba);
try {
Object ret = is.readObject();
return ret;
} finally {
is.close();
}
} finally {
ba.close();
}
} catch (Throwable ex) {
return null;
}
}
public final String getAsString(Object obj) {
//simply do the opposite
}
}
It is structured such a way in order to allow future changes impact all subclasses (ie. avoid base64, be more efficient...). For now, the java.io solution is a temporary implementation.
Then I have the following inside the same WAR:
public class MyPojo implements Serializable {
//Stuff
}
public final class MyPojoConverter extends ConverterBase<MyPojo> { }
The class that extends this one is in a different archive than the abstract class and is specialized on an type of that WAR.
What could I do to avoid that error?
Thank you
If you want to store the data as String, I would use XML or JSon to serialise your objects with a tool like XStream. These tools are not sensitive to change in packages, class names, parent classes, interfaces or method changes.
The ObjectInputStream must be able to access all the classes which are used in the serialized objects.
Normally it should be enough if the code creating the thread (e.g. its classloader) can load each class mentioned in the stream. Make sure this is the case. (I'm not really sure about your class loader structure in your application container. If you provide more information about this, maybe others can help.)
For more complicated cases, you can create a subclass and override resolveClass there.
This is probably a class loading issue (yeah, of course).
If I got you right, the problem occurs from within your WAR, i.e. a JSP or servlet.
Please provide your stack trace, I'm not sure, which class cannot be found.
I'm trying to read a java file and display in console the package, class and method name. something like this:
File: Test.java
package tspec.test;
public class Test {
public void addTest () {}
public void deleteTest () {}
}
Output:
package name: tspec.test
class name: Test
method name:
addTest
deleteTest
Thanks in advance :)
This can be accomplished using the Java Compiler API (introduced in Java 6). Unfortunately, this solution is limited to Sun's JDK. Therefore, you will have to have that JDK installed and you must include its tools.jar file in your class path.
public void displayInformation(File javaSourceFile) throws Exception {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
// The file manager locates your Java source file for the compiler. Null arguments indicate I am comfortable with its default behavior.
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
// These will be parsed by the compiler
Iterable<? extends JavaFileObject> fileObjects = fileManager.getJavaFileObjects(javaSourceFile);
// Creates a new compilation task. This doesn't actually start the compilation process.
// Null arguments indicate I am comfortable with its default behavior.
CompilationTask task = compiler.getTask(null, null, null, null, null, fileObjects);
// Cast to the Sun-specific CompilationTask.
com.sun.tools.javac.api.JavacTaskImpl javacTask = (com.sun.tools.javac.api.JavacTaskImpl) task;
// The Sun-specific JavacTaskImpl can parse the source file without compiling it, returning
// one CompilationUnitTree for each JavaFileObject given to the compiler.getTask call (only one in our case).
Iterable<? extends CompilationUnitTree> trees = javacTask.parse();
CompilationUnitTree tree = trees.iterator().next();
// Create a class that implements the com.sun.source.tree.TreeVisitor interface.
// The com.sun.source.util.TreeScanner is a good choice because it already implements most of the logic.
// We just override the methods we're interested in.
class MyTreeVisitor extends TreeScanner<Void, Void> {
#Override
public Void visitClass(ClassTree classTree, Void p) {
System.out.println("class name: " + classTree.getSimpleName());
System.out.println("method name:");
return super.visitClass(classTree, p);
}
#Override
public Void visitMethod(MethodTree methodTree, Void p) {
System.out.println(methodTree.getName());
return super.visitMethod(methodTree, p);
}
}
tree.accept(new MyTreeVisitor(), null);
}
When I pass this method a File whose content is your sample, I receive this output:
class name: Test
method name:
addTest
deleteTest
Unfortunately, I haven't yet figured out where the package name is stored.
Reflection and Introspection Java API's.
It's purpose is to introspect Java code and report back about it's contents. With Reflection you can do things like :
Class.forName(className).getDeclaredMethods();
Java also has the Java Mirror API with similiar functionality, but is not as commonly used.
Both of these solutions require no 3rd party libraries or tools.
The only difficult is the java code may not be well formatted. like the function declaration can be spread on multiple lines.
The ultimate solution is to create an automata to tokenize the source code first and then apply some compiler technique to grab what you want from the parsed data.
We use PMD Java code analyzer to solve similar problem.
It is useful.
http://pmd.sourceforge.net/
You don't have to do this by parsing the Java file yourself! Java already contains a way of getting information about its own classes, methods, and packages: it's called reflection.
Have a look at the java.lang.Class class. Each instance of this class represents a particular Java class, and contains methods to return the class name, the package it lives in, the methods it contains, and lots more information.
Also worth looking at is the java.lang.reflect package, since some of the methods of Class return types from this package. The package contains classes to represent things like methods, types, fields, and so on.
To obtain a Class instance of your Test class, you can use the following code:
Class<?> testclass = Class.forName("tspec.test.Test");
This returns a class of an unknown type, which is what the question mark inside the angle brackets means if you're not familiar with generics. Why the type of the class instance is unknown is because you specify the class name with a string, which is parsed at runtime. At compile-time, Java cannot be sure that the string passed to forName even represent a valid class at all.
However, testclass as defined above will be fine for getting the class's name, methods, and containing package.