I need to get type of fields declared in java file (ICompilationUnit).
for (IType type : compilationUnit.getTypes()) {
for (IField iField : type.getFields()) {
typesig = iField.getTypeSignature()
}
}
getTypeSignature() - returns type name, but without the package name.
It's possible to obtain package name using:
IType.resolveType(String typeName)
But this method is heavy and takes some time to complete.
Is there another way to get the full type name (with package)?
When using JDT's Java model, the approach in the question (using IType.resolveType()) is the correct one.
If you need resolved types of many elements consider using an AST with resolved bindings. That way you pay the price for resolving only once.
To use type signature, use this code:
Signature.getSignatureSimpleName(iField.getTypeSignature())
Related
There is a little problem with JavaParser usage.
I've parsed source code file and get all methods from parsed interface. Each method has a few parameters. I can get types of this parameters as string, but I couldn't get original package name or class name of this type. I always get java parser classes names or packages. But I need original package name. En example if parsed method parameter has type String I wont his class name etc.
P.S parsing action is executing in build.gladle before compile task. Reflection is not possible.
Code:
// Create compilation unit for parsed file
CompilationUnit cu = StaticJavaParser.parse(sourceFile);
// Get ClassOrInterfaceDeclaration optional from the compilation unit for parsed file
Optional<ClassOrInterfaceDeclaration> parsedInterfaceOptional =
cu.getInterfaceByName("InterfaceName");
// Get ClassOrInterfaceDeclaration from optional
ClassOrInterfaceDeclaration parsedInterface = parsedInterfaceOptional.get();
for (MethodDeclaration method : parsedInterface.findAll(MethodDeclaration.class)) {
final NodeList<Parameter> parameters = method.getParameters();
// At this step I already have a list of method parameters(parameters).
// I am iterating through the all method parameters and try to get
// original class name or class or package of the parameter type
for (Parameter parameter : parameters) {
// Trying to get original class of the parameter type
Class parameterTypeOriginalClass = parameter.type...
}
Please help if you know how to do it.
Still actual.
JavaParser just parses the provided static source code (i.e. text) so it cannot resolve the actual fully qualified name of the used type. And you cannot get Class from it either. All that you can get using JavaParser is a String with fully qualified name of the used type, e.g. "com.package.Type1"). But you need to do it manually.
For example, you got a string type name "Type1" of the parameter which is "Type1 param"
At first, you need to check if this type is not a primitive type from java.lang. If it does - then the fully qualified name of the type will be java.lang. + type name.
If this is not a primitive, you need to check if this type presents among the import statements of the CompilationUnit. If yes, the fully qualified name of this type can be obtained from the import statement value + type name.
If both first and second items didn't succeed, need to check if an inner class with this type is not declared in this CompilationUnit. If it does - than a fully qualified name will be package of the CompilationUnit + type name.
If even the previous step didn't found anything - need to check if a root class of CompilationUnit extends any superclass or implements any interface and check them correspondingly in the same manner as was checked in item 3.
As you can see, it is not an easy task, but it definitely is a solvable one.
I'm trying to search all the classes in a IJavaProject that extends a certain Interface. This interface is Generic, and I want to get the current type parameters of every implementation.
Now I have the SourceType that represents every implementation, but I can't get the current parameters of this class. Here is an example of my classes:
public class PersonDaoImpl extends AbstractDao<PersonPk, Person> {
...
}
My goal is to get the two parameters PersonPk and Person.
If it's possible to convert this SourceType as class, it would be better to manage it.
Thanks!
To get the type arguments of a type's superclass (IType sourceType) use
String superSignature = sourceType.getSuperclassTypeSignature();
for (String typeArgument : Signature.getTypeArguments(superSignature))
System.out.println(Signature.getSignatureSimpleName(typeArgument));
Utility Signature is org.eclipse.jdt.core.Signature.
To get the next IType from its fully qualified name use:
IJavaProject project = sourceType.getJavaProject();
IType type = project.findType(qualifiedTypeName);
If you have an unresolved type signature (starting with Q), then use this to get the qualified name in the first place:
String[] qualifiedNames = sourceType.resolveType(typeSignature);
See the javadoc for details.
In the IDE, the classes in your workspace are not loaded as Class into the current JVM (which runs the IDE), because each change of a file in your workspace would require loading a new class into the JVM leading to huge memory problems, so even if this would be possible by some hack, it is strongly discouraged! The existing representations (Java model & AST) should suffice for all your processing needs.
I need to create a method that takes in argument any attribute of any class. But i dont want it to be of type String, to avoid refactoring problems while renaming an attribute and to get the errors in Markers Tab of eclipse, and not while running my application.
Having a class Person :
public class Person {
private String name;
// other attributes...
// getters and setters...
}
Now the needed method :
void getAnAttributeOfAClass( <which_type_or_class_here?> attr_as_arg){
// Now I need to get the name of attribute that would be of class Strin...
}
Is there a function or a method, by which we can specify an attribute?
For example :
Person.class.name
Would it be of class Property ?
EDIT
More exactly (#Smallhacker answer helped me), I need to verify at compile time if the argument is really an attribute of the specified class.
Person.class.name // no compile time error
Person.class.nameXXX // compile time error
The closest to what you want is Reflection API's Field or JavaBeans Introspector API's PropertyDescriptor.
But usually things like that are not needed in Java projects because there are libraries which handle these concerns.
You could pass a Class object along with a String name, then let your method use Introspector internally to read that property.
Not sure I understand you well, but there is a class java.lang.reflect.Field, that has a method getName() that would give your the name of the field.
In your example, to get field name, you would do: Person.class.getDeclaredField("name").
EDIT: to get the value of a field in an object, you would do: field.get(obj);
OK, let's say You have the following variables:
Person person = ...; // initialized with some Person
Field nameField = Person.class.getDeclaredField("name");
Now to get the name of person, you would do:
String personName = (String)nameField.get(person);
Actually, this would throw an exception because name is a private field. You can however bypass the protection by doing:
nameField.setAccessible(true);
Unfortunately, Java lacks an ability to reference member variables in a way that can be analyzed at compile time.
There may be some kind of library to simplify this somewhat, but it wouldn't provide a full solution due to limitations in the language itself.
Maybe java generics can help you with this.
You can do something like:
class YourClass<E> {
void getAnAttributeOfAClass(E attr_as_arg){
// some code
}
}
someVariable = new YourClass<Person>();
someVariable.getAnAtributeOfAClass(someObject); //this will not compile if someObject is not an instance of Person
But I still don't know what you want to do exactly inside the method.
In Java 6, imagine I have the following method signature:
public void makeSandwich(Bread slice1, Bread slice2, List<Filling> fillings, boolean mustard)
I would like to know, at runtime, the value that was passed on to slice2 or any other parameter, the important bit here is that I want to get the value by parameter name.
I know how to get the list of parameter types with getParameterTypes or getGenericParameterTypes.
Ideally I would like to get a list of parameter names instead of types. Is there a way to do so?
Parameter names are available if you have told the compiler to include them (compile with debug information). Spring has ParameterNameDiscoverer which can help you obtain the names. The default implementation uses asm ClassReader to do so.
With javac you should include the -g argument to include debug information. With Eclipse I think it is there by default; it can be configured using the preferences: Java -> Compiler and then enable "Store information about method parameters (usable via reflection)" (see also this answer).
Some frameworks use this. For example spring-mvc has #RequestParam which defaults to the param name, if resolvable. It also supports explicit naming - #RequestParam("foo") in case no debug information is provided.
I have found another solution after marking this question as answered. The solution is Paranamer.
Example:
Method method = Foo.class.getMethod(...);
Paranamer paranamer = new CachingParanamer();
String[] parameterNames = paranamer.lookupParameterNames(method) // throws ParameterNamesNotFoundException if not found
// or ...
parameterNames = paranamer.lookupParameterNames(method, false) // will return null if not found
Since Java 1.8, this can be done as long as the parameter names are in the class files. Using javac this is done passing the -parameters flag. From the javac help
-parameters Generate metadata for reflection on method parameters
From IDEs you will need to look at the compiler settings.
If the parameter names are in the class files then here is an example of doing this
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
public class ParameterNamesExamples {
public static void main(String[] args) throws Exception {
Method theDoSomethingMethod = ExampleClass.class.getMethods()[0];
// Now loop through the parameters printing the names
for(Parameter parameter : theDoSomethingMethod.getParameters()) {
System.out.println(parameter.getName());
}
}
private class ExampleClass {
public void doSomething(String myFirstParameter, String mySecondParameter) {
// No-op
}
}
}
The output will depend on if the parameter names are in the class files. If they are the output is:
myFirstParameter
mySecondParameter
If not the output is:
arg0
arg1
More information on this from Oracle can be found at Obtaining Names of Method Parameters
In addition to this answer:
"Parameter names are available if you have told the compiler to include them"
If you're using Eclipse go to project -> properties -> Java Compiler -> check "Store information about method parameters (usable via reflection)
In Java parameter names are not available via reflection.
This is not possible. Class files do not contains the argument names, as you can see with your IDE's autocompletion when the source is not available.
Therefore, the reflection API is not able to give out parameter names.
You can simply assign the value of the parameter to another value
Bread slice2;
public void makeSandwich(Bread slice1, Bread slice2, List<Filling> fillings, boolean mustard) {
this.slice2 = slice2;
System.out.println(this.slice2.getSomething());
}
Do you own the code of the method? You could annotate the parameters and pass names as arguments #Param("slice1"). Later you will be able to get the annotation and extract parameter name from it.
Typically I could copy values between two java beans, which have identical property names, using BeanUtils with java reflection e.g. PropertyUtils.setProperty(....)
In protobuf Message, we use the message builder class to set the value. This works but I would rather use reflection to automatically copy properties from the bean to the message as both have identical property names and type.
When I invoke the PropertyUtils.setProperty on the builder object ( got from message.newBuilder()), I get this message.
java.lang.NoSuchMethodException: Property 'testProp' has no setter method in class 'class teststuff.TestBeanProtos$TestBeanMessage$Builder'
How do I automatically copy values from java bean to protobuf message object (and vice-versa) using java reflection?
I hate to answer my question but I cant believe that I am the only one who ran into this problem. Documenting solution here in case other people are also getting started with protobuf and java. Using reflection saves wrting dozens of getter and setters.
Ok , I managed to get it to work using some of example test code shipping with protobuf. This is a very simple use case; typically a message would be a lot more complex. This code does not handle nested messages or repeated messages.
public static void setMessageBuilder(com.google.protobuf.GeneratedMessage.Builder message,Descriptors.Descriptor descriptor,Object srcObject) throws Exception {
String cname = srcObject.getClass().getName();
/*BeanMapper.getSimpleProperties -- this is a warpper method that gets the list of property names*/
List<String> simpleProps = BeanMapper.getSimpleProperties(srcObject.getClass());
Map map = new HashMap();
for (String pName : simpleProps) {
System.out.println(" processing property "+ pName);
Object value= PropertyUtils.getProperty(srcObject, pName);
if(value==null) continue;
Descriptors.FieldDescriptor fd=descriptor.findFieldByName(pName) ;
System.out.println(" property "+ pName+" , found fd :"+ (fd==null ? "nul":"ok"));
message.setField(fd, value);
System.out.println(" property "+ pName+" set ok,");
}
return ;
}
I may be off, but would protostuff help? It has nice extended support for working with other data formats, types. And even if it didn't have direct conversion support, if you go to/from JSON there are many choices for good data binding.
You can go throw all properties getClass().getFields() and make copy using reflection. It will be smt like:
for(Field f : to.getClass().getFields()){
f.set(to, from.getClass().getField(f.getName()).get(from));
}
+ probably you might be use field.setAccessible(true) invocation.
I don't know the size of your project but you may want to try Dozer, a mapper that recursively copies data from one object to another of the same type or between different complex types. Supports implicit and explicit mapping as well. I used it in a big project and worked very well. It could be as simple as
Mapper mapper = new DozerBeanMapper();
DestinationObject destObject = mapper.map(sourceObject, DestinationObject.class);
I've got the same issue, the solution is a little bit tricky.
Please use
MethodUtils.invokeMethod
instead.
where the method name is "setXXX".