How to pass PHP class as parameter to a builder function? - java

I implemented an object builder which takes a class name and tries to create a new instance object. The builder tries to inject services if any required. The class name is passed as a string in the current implementation. Here is an example
$className = '\Example\Application\ServiceClass';
$service = CiContext::newInstance($className);
However, this is not compatible with my IDE (eclipse) and the refactoring process does not find the class name (in the string form).
Is there any way to get the class name like java does?
Class classInstance = ServerClass.class;
In this case, the refactoring process finds the class reference and changes the class name.

Well, PHP7 class constant is supported on a class name. For example, the following code is correct in PHP 7.4:
$service = CiContext::newInstance(\Example\Application\ServiceClass::class);
This will solve my problem and the IDE find the class usage.
On the other hand, the class literal is going to support for objects too. For more information see class literal on object

Related

Eclipse: SourceType to Class (or get current parameters of the Class)

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.

How to get as a stream any class loaded from a jar not in the classpath?

I have a web-app which I want to work roughly as follows:
Someone uploads a jar (say myjar.jar) along with the name of class to analyze (say test.Test). The exact purpose of analysis is irrelevant so assume that the web-app does some static analysis on it.
I am able to upload the jar and load the class in Java using the hacks described here and here (MultiClassLoader).
If I know the methods inside the class, I can invoke them using reflection. Following assumes a method with signature foo(String)
Class c = jarLoader.loadClass("test.Test", true);
Object instance = c.newInstance();
Method foo = instance.getClass().getDeclaredMethod("foo", new Class[]{String.class});
// foo takes one para String
foo.setAccessible(true);
foo.invoke(instance, (Object) "hello");
Now, suppose, I need to find out what methods are there inside test.Test. To do this, I use the ASM framework, which needs the class as a stream. This is where I am running into a problem. I am unable to do getResourceAsStream or its equivalents. This is what I tried:
Type t = org.objectweb.asm.Type.getType(c); // uses asm library
String url = t.getInternalName() + ".class";
c.getClassLoader().getResourceAsStream(url); // gives null
Same problem if I use:
c.getClassLoader().getResourceAsStream(c.getSimpleName() + ".class");
etc.
What is the right way to get resource as stream, where the resource is a class file loaded from a jar NOT in the class path. Note that the entire thing is done via a web-app.
EDIT: Getting methods is just an example. What I really want is to get the class as a stream. I need to use ASM because it gives me other information (such as parameter names), which I cannot get via getDeclaredMethods or getMethods.
Re: "Now I need to find out what methods are there inside test.Test"
You get the class via Class c = jarLoader.loadClass("test.Test", true);. Class also has getDeclaredMethods() and getMethods().
EDIT: #Jus12, from your second link Java Tip 70: Create objects from jar files!:
protected byte[] loadClassBytes (String className)
ASM has a ClassReader(byte[] b) constructor.
You can use a URLClassLoader, which takes a List of URLs in its constructor. You can then load the class by invoking the loadClass method on the URLClassLoader instance to get the Class<?> object for the class that you are after. Once you have that, you can then use reflection to create instances, and/or get general information about the class.
I have not tried, but the URLClassLoader does also have a getResourceAsStream method.

Java : method that takes in argument any attribute of any class

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.

How to convert String type to Class type in java

I want to print all the class names in a package and also to print the corresponding attributes and their data types in each package.
In one code, I am able to get the classnames in the form of string.
In another code I am able to get the attributes and their data types using Classname.class.getAttribute();
However I want to merge the two codes. Since in the first code I got the classnames in the form of string , I can't use Classname.class.getAttribute() since here Classname will be of type String.
So I want a method which will convert the "Classname" from String type to Class type.
I tried Class.forName() but it didn't work.
Class<?> classType = Class.forName(className);
Make sure className is fully qualified class name like com.package.class Also, please share your error message that you see.
If the fully-qualified name of a class is available, it is possible to get the corresponding Class using the static method Class.forName().
Eg:
Class c = Class.forName("com.duke.MyLocaleServiceProvider");
Note: Make sure the parameter you provide for the function is fully qualified class name like com.package.class
Check here for any reference.
EDIT:
You could also try using loadClass() method.
Eg:
ClassLoader cl;
Class c = cl.loadClass(name);
It is invoked by the Java virtual machine to resolve class references.
Syntax:
public Class<?> loadClass(String name)
throws ClassNotFoundException
For details on ClassLoader check here
Here
is an implementation of ClassLoader.
Please try as following.
String str = "RequiredClassName";
Class <?> Cref = Class .forName("PackageNaem."+str );

Getting method via reflection

My previous post was not very clear, sorry for that. I will try to give a better example of what I am trying to do.
I have an Java application that will load .class files and runs them in a special enviroment (the Java app has built-in functions) Note: This is not a library.
That Java application will then display an applet, and I want to modify the variables in the applet.
The main class of the applet is called 'client'.
The Java application will load the applet by creating an new instance of class 'client'.
I already got access to the 'client' class. the Java application will put the applet in a variable:
Applet client = (Applet) loadedClientClass.newInstance();
So I did this:
Class<?> class_client = client.getClass();
I can now read and set the fields but the 'client' class will call a funation of an other class, like this:
otherClass.someVoid(false);
And if I try something like:
class_client.getDeclaredMethod("otherClass.someVoid",boolean.class);
It will fail, saying that the function can not be found.
'otherClass' is the direct class name, it is not a reference to a new instance of the class as far as I know.
Is there any way to get 'otherClass.someVoid'?
You're using getDeclaredMethod like a static method (expecting it to return methods from any class), but it only returns method from the class itself. Here's how you can call otherClass.someVoid(false).
Class<?> otherClass = Class.forName("com.xyz.OtherClass"); // Get the class
Method method = otherClass.getDeclaredMethod("someVoid", boolean.class);
// If the method is an Class (ie static) method, invoke it on the Class:
method.invoke(otherClass, false);
// If the method is an instance (ie non-static) method, invoke it on an instance of the Class:
Object otherInstance = otherClass.newInstance(); // Get an instance of other class - this approach assumes there is a default constructor
method.invoke(otherInstance, false);
If the class isn't initialized, the var someInteger doesn't exist. It's a member variable, so it only exists inside of instances of the class. So, you can't change it since it's doesn't exist. Now, if you made it a static variable, then you could change it.
Is there any way to change 'otherClass.someInteger' through the
'mainClass' class?
No.
But you can get it via OtherClass' class via Class.forName:
Class<?> theOtherClazz = Class.forName("OtherClass");
And then get the methods via theOtherClazz.getDeclaredMethod

Categories