JDT ASTParser to get the value of a string field - eclipse

Is there a way to use jdt ASTParser to get the value of a String field declared in a java file. Actually what I need is to resolve any possible dependencies from other classes e.g.
public String str = "somethig"+SomeTherClass.SOMETHING_ELSE.

I figured it out ...it was quite simple actually ..here's the code:
ICompilationUnit cu = ....
ASTParser parser = ASTParser.newParser(AST.JLS3);
parser.setResolveBindings(true);
parser.setSource(cu);
parser.setStatementsRecovery(true);
parser.setBindingsRecovery(true);
ASTNode node = parser.createAST(null);
node.accept(new YourVisitor());
Then in your implementation of the ASTVisitor you need to call resolveConstantExpressionValue() on the node being visited.

Related

Wicket NumberTextField in Kotlin throws ClassCastException when submitted

I'm having some issues with a Wicket (8.0.0-M4) NumberTextField in Kotlin (1.1.0).
My stripped-down form looks like this:
class Test : AbstractWebPage() {
val housenumberModel: Model<Int> = Model<Int>()
val housenumber = NumberTextField<Int>("housenumberModel", housenumberModel)
val form: Form<Unit> = object : Form<Unit>("adressForm") {}
override fun onInitialize() {
super.onInitialize()
form.add(housenumber.setRequired(false))
form.add(object : SubmitLink("submit") {
override fun onSubmit() {
super.onSubmit()
println(housenumberModel.`object`) // this is line 28
}
})
add(form)
}
}
After submitting the form I get the following stacktrace:
java.lang.ClassCastException: java.lang.String cannot be cast to
java.lang.Number
at com.mycompany.test.pages.Test$onInitialize$1.onSubmit(Test.kt:28)
at org.apache.wicket.markup.html.form.Form.delegateSubmit(Form.java:1312)
at org.apache.wicket.markup.html.form.Form.process(Form.java:979)
at org.apache.wicket.markup.html.form.Form.onFormSubmitted(Form.java:802)
at org.apache.wicket.markup.html.form.Form.onRequest(Form.java:715)
at org.apache.wicket.core.request.handler.ListenerRequestHandler.internalInvoke(ListenerRequestHandler.java:301)
at org.apache.wicket.core.request.handler.ListenerRequestHandler.invoke(ListenerRequestHandler.java:250)
at org.apache.wicket.core.request.handler.ListenerRequestHandler.invokeListener(ListenerRequestHandler.java:210)
at org.apache.wicket.core.request.handler.ListenerRequestHandler.respond(ListenerRequestHandler.java:203)
at org.apache.wicket.request.cycle.RequestCycle$HandlerExecutor.respond(RequestCycle.java:912)
at org.apache.wicket.request.RequestHandlerExecutor.execute(RequestHandlerExecutor.java:65)
at org.apache.wicket.request.cycle.RequestCycle.execute(RequestCycle.java:283)
at org.apache.wicket.request.cycle.RequestCycle.processRequest(RequestCycle.java:253)
at org.apache.wicket.request.cycle.RequestCycle.processRequestAndDetach(RequestCycle.java:221)
at org.apache.wicket.protocol.http.WicketFilter.processRequestCycle(WicketFilter.java:262)
at org.apache.wicket.protocol.http.WicketFilter.processRequest(WicketFilter.java:204)
at org.apache.wicket.protocol.http.WicketFilter.doFilter(WicketFilter.java:286)
[...]
If I use
val housenumberModel: Model<Int> = Model.of(0)
instead of
val housenumberModel: Model<Int> = Model<Int>()
everything works fine. But since my NumberTextField is optional I don't want to have it pre-initialized with 0.
Me and my colleagues were trying to change the type signature of the Model in every way we could imagine but came to no solution. A co-worker suggested to write a custom Wicket converter since Kotlins Int is represendeted as a primitive type (From the docs: "On the JVM, non-nullable values of this type are represented as values of the primitive type int.") Even though I don't know yet if this would work it seems like an overkill for me.
Another hack I could think of: writing some JavaScript to delete the zero from the input field. Also not really something I would want to do.
Question: Is there a simple solution to my problem?
(And as a bonus-question: has already anyone written a larger Wicket application in Kotlin and could tell me if this combination is ready for prime time to develop a critical project with this stack or is my problem just the tip of the iceberg?)
[edit]
Solution as pointed out by svenmeier:
Using
val housenumber = NumberTextField<Int>("housenumberModel", housenumberModel, Int::class.java)
works.
Or as an alternative:
val housenumbervalue: Int? = null
val housenumberModel: IModel<Int> = PropertyModel<Int>(this, "housenumbervalue")
val housenumber = NumberTextField<Int>("housenumberModel", housenumberModel)
Because of type erasure your NumberTextField cannot detect the generic type parameter of your model. Since your model object is null, it cannot be used to derive the type either.
In this case Wicket assumes a String model object type :/.
Either provide the type to the NumberTextField explicitly, or use a model that keeps its generic information, e.g. a PropertyModel.
There is a way to tell wicket about the type you want, it is by adding the type in the constructor. More here.
In Java it looks like this:
new NumberTextField<Integer>("housenumberModel", housenumberModel, Integer.class);

How to set the background colour of elements according to their visibility modifier in Eclipse?

I'd like to set the background colour of fields and methods (on the first level) according to their visibility modifier in Eclipse.
For example private fields and methods should get a red background, while public fields and methods get a green background:
Is there a way to configure this in Eclipse?
To get this sort of a colored background, you need to use Markers and MarkerAnnotationSpecification. You will find how to use them here: http://cubussapiens.hu/2011/05/custom-markers-and-annotations-the-bright-side-of-eclipse/
As for how to find the private, public fields, you need to use the JDT plugin and the AST parser to parse the Java file and find all the information that you want. I am adding a small code snippet to get you started on this.
ASTParser parser = ASTParser.newParser(AST_LEVEL);
parser.setSource(cmpUnit);
parser.setResolveBindings(true);
CompilationUnit astRoot = (CompilationUnit) parser.createAST(null);
AST ast = astRoot.getAST();
TypeDeclaration javaType = null;
Object type = astRoot.types().get(0);
if (type instanceof TypeDeclaration) {
javaType = ((TypeDeclaration) type);
}
List<FieldDeclarationInfo> fieldDeclarations = new ArrayList<FieldDeclarationInfo>();
// Get the field info
for (FieldDeclaration fieldDeclaration : javaType.getFields()) {
// From this object you can recover all the information that you want about the fields.
}
Here cmpUnit is the ICompilationUnit of the Java File.

Eclipse JDT static field modifiers

I want to get the information about a field modifier. To be precise, I want to find out is the field a static one. For example, I want to examine the following code:
ASTParser parser = ASTParser.newParser(AST.JLS3);
How can I infer that the JLS3 is static field? I used getModifiers with Modifier.isStatic when analyzing methods and it worked fine. However, now I am not able to get the information that JLS3 in above code snippet is a static field. Is there something I am missing?
EDIT:
This is the code that I am using:
private boolean visit(SimpleName name){
boolean isStatic = Modifier.isStatic(name.resolveTypeBinding().getModifiers());
...
return true;
}
isStatic is false in the case of JLS3.
That's obviously wrong, use name.resolveBinding() instead of name.resolveTypeBinding() --- so you should get an object of type IVariableBinding.
name.resolveTypeBinding() returns the binding for the type of the field, but not the binding of field itself, which is not what you want here.

How to generate multiple values for a class level annotation using JDT

We are using JDT for generating java source code. We are stuck in generating a class where the class itself is annotated as belows:
#SomeAnnotation({Class1.class, Class2.class})
Please let me know how this can be achieved. I am using NormalAnnotation class for this but could not set the expression accordingly. Though String literals can be set but Class cannot be.
I was able to do this using NormalAnnotation class, here is the code:
// values contains the class names.
NormalAnnotation normalAnnotation = ast.newNormalAnnotation();
Name name = ast.newName(annotationName);
normalAnnotation.setTypeName(name);
ArrayInitializer arrayInit = ast.newArrayInitializer();
for(String value : values){
TypeLiteral tL = ast.newTypeLiteral();
tL.setType(ast.newSimpleType(ast.newName(value)));
arrayInit.expressions().add(tL);
}
MemberValuePair memberValuePair = ast.newMemberValuePair();
memberValuePair.setName(ast.newSimpleName("value"));
memberValuePair.setValue(arrayInit);
normalAnnotation.values().add(memberValuePair);

How could I search references to a field on a AST or a CompilationUnit in eclipse?

Hi,
I'm developing an Eclipse plugin. I
need to find all the references in the
source using AST's or jdt.core.dom
or something like that. I need this
references like ASTNodes in order to
get the parent node and check several
things in the expression where
references are involved.
Thanks beforehand.
Edited:
I want to concrete a little more, My problem is that I try to catch some references to a constant but... I have not idea how I can do to catch in the matches this references. I need check the expressions which the references to a determined constant are involved. I only get the source of the method where they are used.
I think the problem is the scope or the pattern:
pattern = SearchPattern.createPattern(field, IJavaSearchConstants.REFERENCES);
scope = SearchEngine.createJavaSearchScope(declaringType.getMethods());
Thanks beforehand!
I used something like:
Search for the declaration of an
method, returns an IMethod
Search for references to the
IMethod, record those IMethods
For each IMethod returned, create an
AST from its compilation unit
Searching for declarations or references looks like the following code.
SearchRequestor findMethod = ...; // do something with the search results
SearchEngine engine = new SearchEngine();
IJavaSearchScope workspaceScope = SearchEngine.createWorkspaceScope();
SearchPattern pattern = SearchPattern.createPattern(searchString,
IJavaSearchConstants.METHOD, IJavaSearchConstants.DECLARATIONS,
SearchPattern.R_EXACT_MATCH);
SearchParticipant[] participant = new SearchParticipant[] { SearchEngine
.getDefaultSearchParticipant() };
engine.search(pattern, participant, workspaceScope, findMethod,
monitor);
Once you have your IMethod references, you can get to the AST using:
ASTParser parser = ASTParser.newParser(AST.JLS3);
parser.setResolveBindings(true);
if (methodToSearch.isBinary()) {
parser.setSource(methodToSearch.getClassFile());
} else {
parser.setSource(methodToSearch.getCompilationUnit());
}
CompilationUnit cu = (CompilationUnit) parser.createAST(null);
See http://help.eclipse.org/helios/index.jsp?topic=/org.eclipse.jdt.doc.isv/guide/jdt_int_core.htm for more details on java search, the java model, and the AST.