How would one go about instantiating an Enum type via a ClassLoader or similar mechanism? (I'm trying to keep everything under the same context classloader for a standalone server application).
I have something like:
ClassLoader loader = new CustomClassLoader(parent, libDir);
Thread.currentThread().setContextClassLoader(loader);
// trouble area
Class<?> containerClass = loader.loadClass("com.somepackage.app.Name$SERVER");
I had wrongly thought simply loading the Enum would be enough to kick it off (it's private constructor contains startup method calls and what-not).
Doing what I have above does not result in any exceptions, but the JVM just terminates after the last line and the server does not start up.
Obviously doing:
containerClass.newInstance();
Results in an exception being thrown.
To expand on my comment, I think the cleanest you'll get is something like this:
public static <T extends Enum<T>> T loadEnum(ClassLoader loader, String classBinaryName, String instanceName) throws ClassNotFoundException {
#SuppressWarnings("unchecked")
Class<T> eClass = (Class<T>)loader.loadClass(classBinaryName);
return Enum.valueOf(eClass, instanceName);
}
There is really no way to avoid the unchecked cast from Class<?> to a proper enum type. But at least the #SuppressWarnings is limited in scope.
Edit:
Upon further checking, there is actually a simpler way of achieving what you need, without needing to know the name of an instance and without warnings:
Class<?> containerClass = loader.loadClass("com.somepackage.app.Name");
containerClass.getEnumConstants()
Loading an enum doesn't cause it to initialize. You have to reference it through either a field reference or a method reference. So even a simple statement like Name name = Name.SERVER; or Name.SERVER.name(); would do the trick.
See section 5.5 Initialization in chapter 5. Loading, Linking, and Initializing of the Java Virtual Machine Specification.
Related
Suppose the following:
#SomeAnnotation
public interface Foo {
}
I would like to know if it is always the case that either the defining classloader of SomeAnnotation is equal to or a parent of the initiating classloader of Foo.
I have read JVMS v8 section 5.3. but I'm not sure what applies here. Section 5.3.4 talks about loading constraints, but they seem not to apply for annotations.
The question I'm asking is because code like this:
Class<?> fooClass = //will in some way obtain a reference to class Foo
fooClass.getAnnotation(SomeAnnotation.class);
will fail in the presence of different classloaders. I know I could use getAnnotations and search in the resulting array for an element whose class name is equal to the name of SomeAnnotation. But I'm wondering if the following will work too:
Class<?> fooClass = //will in some way obtain a reference to class Foo
fooClass.getAnnotation((Class<? extends Annotation>) fooClass
.getClassLoader().loadClass(SomeAnnotation.class.getName()));
The short answer: no
The long answer.
RetentionPolicy.RUNTIME annotations are available for discovery via the reflection API only. This is done to ensure loose coupling between annotations and annotated code. According to this bug report, getAnnotations() must skip unknown annotations which implies that it's ok to have annotations that are not recognized by the classloader. The behavior of real Java code discussed here validates that assumption.
This behavior has two implications:
All unrecognized annotations (e.g. the ones not in classpath) become "invisible"
In order to reveal them, the class must be completely reloaded by a different classloader that has access to both, the type and annotations.
For example if somepkg.SomeAnnotation was not in classpath when someClass was loaded, this will not work:
Class<?> someClass = ....
URL [] classPathWithAnnotations = ....
ClassLoader cl = new URLClassLoader(classPathWithAnnotations);
Annotation a = someClass.getAnnotation(cl.loadClass("somepkg.SomeAnnotation"));
// a will be null
But this will:
Class<?> someClass = ....
URL [] classPathWithSomeClassAndAnnotations = ....
ClassLoader cl = new URLClassLoader(classPathWithSomeClassAndAnnotations, null);
Annotation a = cl.loadClass(someClass.getName()).getAnnotation(cl.loadClass("somepkg.SomeAnnotation"));
I'm looking at some Java reflection sourcecode that goes like this:
Method fixTransparentPixels = TextureAtlasSprite.class.getDeclaredMethod("fixTransparentPixels", new Class[] { [[I.class });
The method being referenced is declared like so:
private void fixTransparentPixels(int[][] p_147961_1_) {...}
What I do not understand is the [[I.class part. Now, I get that the actual Class[] array is to determine which form of the declared method you want (what parameter types etc.), but what does [[I.class actually mean?
Furthermore, when I try to write this reflection code myself, my IDE gives me syntax errors on the [[I.class bit. Can anyone give me any info on this?
Cheers.
When using getDeclaredMethod(String name, Class<?>... parameterTypes) the parameterTypes must be the class of the parameter (obviously). So in this case fixTransparentPixels require a int[][], so the parameterTypes will be int[][].class.
This will works :
TextureAtlasSprite.class.getDeclaredMethod("fixTransparentPixels", int[][].class);
[[I is the internal name of the class for int[][]:
System.out.println(int[][].class.getName()); outputs [[I
or Class.forName("[[I") == int[][].class.
However, it's illegal to write [[I.class in source code. You should write int[][].class instead.
I'm having problems with an MBean that takes a Map<String, Object> as a parameter. If I try to execute it via JMX using a proxy object, I get an Exception:
Caused by: javax.management.ReflectionException
at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:231)
at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:668)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
Caused by: java.lang.IllegalArgumentException: Unable to find operation updateProperties(java.util.HashMap)
It appears that it attempts to use the actual implementation class rather than the interface, and doesn't check if this is a child of the required interface. The same thing happens for extended classes (for example declare HashMap, pass in LinkedHashMap). Does this mean it's impossible to use an interface for such methods? At the moment I'm getting around it by changing the method signature to accept a HashMap, but it seems odd that I wouldn't be able to use interfaces (or extended classes) in my MBeans.
Edit: The proxy object is being created by an in-house utility class called JmxInvocationHandler. The (hopefully) relevant parts of it are as follows:
public class JmxInvocationHandler implements InvocationHandler
{
...
public static <T> T createMBean(final Class<T> iface, SFSTestProperties properties, String mbean, int shHostID)
{
T newProxyInstance = (T) Proxy.newProxyInstance(iface.getClassLoader(), new Class[] { iface }, (InvocationHandler) new JmxInvocationHandler(properties, mbean, shHostID));
return newProxyInstance;
}
...
private JmxInvocationHandler(SFSTestProperties properties, String mbean, int shHostID)
{
this.mbeanName = mbean + MBEAN_SUFFIX + shHostID;
msConfig = new MsConfiguration(properties.getHost(0), properties.getMSAdminPort(), properties.getMSUser(), properties.getMSPassword());
}
...
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
if (management == null)
{
management = ManagementClientStore.getInstance().getManagementClient(msConfig.getHost(),
msConfig.getAdminPort(), msConfig.getUser(), msConfig.getPassword(), false);
}
final Object result = management.methodCall(mbeanName, method.getName(), args == null? new Object[] {} : args);
return result;
}
}
Got it. JMX invocations sometimes make cannon-fodder of the best intended utility classes .... :)
This guy, I suspect, is a problem:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
if (management == null)
{
management = ManagementClientStore.getInstance().getManagementClient(msConfig.getHost(),
msConfig.getAdminPort(), msConfig.getUser(), msConfig.getPassword(), false);
}
final Object result = management.methodCall(mbeanName, method.getName(), args == null? new Object[] {} : args);
return result;
}
because the MBean's operation signature (which cares not a whit about inheritance) is determined from the classes of the passed arguments. Since you cannot pass an actual concrete object for which getClass() will return java.util.Map, you will never make a match using the direct types of the arguments themselves. (Similar problems occur with primitives for the same reason).
See this blog post starting with the paragraph opening with "One of the tricky parts of making MetaMBean", as it explains this problem (or the problem I think you're having) in a bit more detail, but the invoke method of the MBeanServer[Connection] is:
invoke(ObjectName name, String operationName, Object[] params, String[] signature)
The first 2 and the last arguments are navigational in that they specify exactly which operation amongst all the ops published in the server should be invoked. The best way to sidestep this issue is to avoid having to "guess" the signature and only rely on the ObjectName and the operation name, which in turn can be done by interrogating (and possibly caching) the MBeanInfo and MBeanOperationInfos of the target MBean. The MBeanOperationInfos will provide you the signature so you don't have to guess.
If this is indeed your issue, there's a couple of ways you can address it:
If the MBean's operation names are unique (i.e. there's no overloading) then you can just use the op name to retrieve the MBeanInfo.
If the MBean's operation is overloaded (i.e. there are multiple operations with the same name but different parameters)... but they all have different parameter counts, then you can easilly determine the correct signature by iterating all the matching op names in the MBeanOperationInfos and matching by param count.
If #1 and #2 do not apply.... then it's tricky and I would re-evaluate the method signatures of your MBean's code.
If #1 and #2 do not apply and #3 will not comply, take a look at this class in Gmx called MetaMBean. In the latest revision, it uses Groovy to create a compiled runtime interface using the MBean's MBeanInfo to make inheritance (and autoboxing) work in method invocation. The same method could be implemented in JavaScript (which has the virtue of being built into Java 6+) or several other JVM scripting languages. Alternatively, look at the previous version which attempted to pattern match against known operation signatures (and worked pretty well actually, but since I was working with Groovy anyways......)
I hope this is helpful. If this turns out not to be the root cause, then forget I said anything....
I have a class that must have some static methods. Inside these static methods I need to call the method getClass() to make the following call:
public static void startMusic() {
URL songPath = getClass().getClassLoader().getResource("background.midi");
}
However Eclipse tells me:
Cannot make a static reference to the non-static method getClass()
from the type Object
What is the appropriate way to fix this compile time error?
The Answer
Just use TheClassName.class instead of getClass().
Declaring Loggers
Since this gets so much attention for a specific usecase--to provide an easy way to insert log declarations--I thought I'd add my thoughts on that. Log frameworks often expect the log to be constrained to a certain context, say a fully-qualified class name. So they are not copy-pastable without modification. Suggestions for paste-safe log declarations are provided in other answers, but they have downsides such as inflating bytecode or adding runtime introspection. I don't recommend these. Copy-paste is an editor concern, so an editor solution is most appropriate.
In IntelliJ, I recommend adding a Live Template:
Use "log" as the abbreviation
Use private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger($CLASS$.class); as the template text.
Click Edit Variables and add CLASS using the expression className()
Check the boxes to reformat and shorten FQ names.
Change the context to Java: declaration.
Now if you type log<tab> it'll automatically expand to
private static final Logger logger = LoggerFactory.getLogger(ClassName.class);
And automatically reformat and optimize the imports for you.
As for the code example in the question, the standard solution is to reference the class explicitly by its name, and it is even possible to do without getClassLoader() call:
class MyClass {
public static void startMusic() {
URL songPath = MyClass.class.getResource("background.midi");
}
}
This approach still has a back side that it is not very safe against copy/paste errors in case you need to replicate this code to a number of similar classes.
And as for the exact question in the headline, there is a trick posted in the adjacent thread:
Class currentClass = new Object() { }.getClass().getEnclosingClass();
It uses a nested anonymous Object subclass to get hold of the execution context. This trick has a benefit of being copy/paste safe...
Caution when using this in a Base Class that other classes inherit from:
It is also worth noting that if this snippet is shaped as a static method of some base class then currentClass value will always be a reference to that base class rather than to any subclass that may be using that method.
In Java7+ you can do this in static methods/fields:
MethodHandles.lookup().lookupClass()
I wrestled with this myself. A nice trick is to use use the current thread to get a ClassLoader when in a static context. This will work in a Hadoop MapReduce as well. Other methods work when running locally, but return a null InputStream when used in a MapReduce.
public static InputStream getResource(String resource) throws Exception {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
InputStream is = cl.getResourceAsStream(resource);
return is;
}
Simply use a class literal, i.e. NameOfClass.class
Try it
Thread.currentThread().getStackTrace()[1].getClassName()
Or
Thread.currentThread().getStackTrace()[2].getClassName()
getClass() method is defined in Object class with the following signature:
public final Class getClass()
Since it is not defined as static, you can not call it within a static code block. See these answers for more information: Q1, Q2, Q3.
If you're in a static context, then you have to use the class literal expression to get the Class, so you basically have to do like:
Foo.class
This type of expression is called Class Literals and they are explained in Java Language Specification Book as follows:
A class literal is an expression consisting of the name of a class, interface, array, or primitive type followed by a `.' and the token class. The type of a class literal is Class. It evaluates to the Class object for the named type (or for void) as defined by the defining class loader of the class of the current instance.
You can also find information about this subject on API documentation for Class.
I had the same problem !
but to solve it just modify your code as following.
public static void startMusic() {
URL songPath = YouClassName.class.getClassLoader().getResource("background.midi");
}
this worked fine with me hope it will also work fine with you.
Suppose there is a Utility class, then sample code would be -
URL url = Utility.class.getClassLoader().getResource("customLocation/".concat("abc.txt"));
CustomLocation - if any folder structure within resources otherwise remove this string literal.
Try something like this. It works for me. Logg (Class name)
String level= "";
Properties prop = new Properties();
InputStream in =
Logg.class.getResourceAsStream("resources\\config");
if (in != null) {
prop.load(in);
} else {
throw new FileNotFoundException("property file '" + in + "' not found in the classpath");
}
level = prop.getProperty("Level");
I want to instantiate a class by the value of a String. I found several tutorials that show several methods for doing this. The class MUST inherit from a certain interface, ImplementMe which has a special method called runMe(). So here's what I tried:
ImplmentMe a =
(ImplementMe) ImplementMe.class
.getClassLoader()
.loadClass("my.package.IImplementedYou")
.newInstance();
a.runMe();
It works, but it's so ugly. I at least expected not needing a cast. Please tell me there is a better way.
No, there is no better way (by design). You are not supposed to do this, Java is designed as a type-safe language. However, I can understand that you sometimes need to do things like this, and for that purposes you can create a library function like this:
public <T> T instantiate(final String className, final Class<T> type){
try{
return type.cast(Class.forName(className).newInstance());
} catch(InstantiationException
| IllegalAccessException
| ClassNotFoundException e){
throw new IllegalStateException(e);
}
}
Now your client code can at least call this method without casting:
MyInterface thingy =
instantiate("com.foo.bar.MyInterfaceImpl", MyInterface.class);
Try Class.forName("my.package.IImplementedYou").
Here's how I would do it:
ImplementMe noCastNeeded =
this.getClassLoader()
.loadClass("my.package.IImplementedYou")
.asSubclass(ImplementMe.class).newInstance();
There are some Exceptions to catch but that's ok I think. :)
In all essence that is what will happen regardless of whether you're using a third party toolkit for it or not. Casting the object will inherently be mandatory unless expecting an Object. You can however make a routine which does that for you:
public <T> T instantiateObject(String name, Class<T> cls) throws Exception {
return (T) Class.forName(name).newInstance();
}
Which you can use:
AClass cls = instantiateObject("com.class.AClass", AClass.class);
But if you come this far, the String name is actually redundant (given AClass is a concrete class). You might as well:
public <T> T instantiateObject(Class<T> cls) throws Exception {
return (T) Class.forName(cls.getCanonicalName()).newInstance();
}
Which you can use:
AClass cls = instantiateObject(AClass.class);
You can shorten it a bit like
ImplementMe a = (ImplementMe) Class
.forName("my.package.IImplementedYou")
.newInstance();
but you can't get rid of the cast. There may be a way to avoid the cast, but only if you can avoid the subproblem of loading class by name.
The alternative is to use forName, but it does not get much better than what you currently have:
ImplementMe a =
(ImplementMe) Class.forName("my.package.IImplementedYou").newInstance();
a.runMe();
Indeed, forName will use getClassLoader().loadClass() behind the scenes to load the class, as you can see in the source code of Class.java.
You will need a cast, because the compiler cannot tell from the code that the object is of type ImplementMe. It thus requires the programmer to issue a cast, which will throw a ClassCastException if the object is not an ImplementMe instance.
What you have may work, but you don't have to load the class using the same classloader that loaded ImplementMe. This should work equally well:
Object newInstance = this.getClass().getClassLoader().loadClass("my.package.IImplementedYou").newInstance();
The important thing is that the classloader knows both the class file with the implementation of "my.package.IImplementedYou" and the class with the implementation of "ImplementMe".
You may explicitly check that IImplementedYou really implements ImplementMe like this:
if(newInstance instanceof my.package.IImplementedYou) {
((ImplementMe)newInstance).runMe();
}
You may also check that IImlementedYou really is implementing the interface before creating the instance:
Class c = this.getClass().getClassLoader().loadClass("my.package.IImplementedYou");
if(ImplementMe.class.isAssignableFrom(c)) {
Object newInstance = c.newInstance();
}
(MyInterface)Class.forName(className).newInstance()