Dynamically casting to primitives in Java - java

Edit: This has since been solved. Thanks to everyone who helped. Invoking the method after casting the object as the correct wrapper class worked. But String.valueOf() is much, much simpler to achieve the same effect.
Hello--
What I'm trying to do may not even be possible. I've spent a few hours now researching and experimenting with various things, so I figured I'd finally ask around to see if anyone knows if this is even possible.
Is it possible, using reflection, to dynamically cast a wrapper for a primitive of an unknown type as a primitive?
I'm basically trying to create a generic toString function which can handle the conversion of any type of primitive to a string. Such a seemingly simple thing is frustratingly difficult (and I am aware I could just test each type to see if it is of type Wrapper.class and cast it specifically, but at this point I'm just pursuing this out of stubbornness).
The following throws a ClassCastException. The primClass class appears to be the right one (gives "int" when printing primClass.getName()).
private String toString(Number obj){
String result = "";
try{
Class objClass = obj.getClass();
Field field = objClass.getDeclaredField("TYPE");
Class primClass = (Class)field.get(obj);
Method method = objClass.getMethod("toString", new Class[]{primClass});
Object args = new Object[]{primClass.cast(obj)};
result = (String)method.invoke(null, args);
}catch(Exception ex){
//Unknown exception. Send to handler.
handleException(ex);
}
return result;
}
So I'm a bit at a loss, really. Anyone have any ideas? Any help would be greatly appreciated.

Perhaps I'm missing something, but obj.toString() would do.
If you look at the implementations, it is calling String.valueOf(value) which in turn calls Double.toString(..) or Long.toString(..) or whatever. So, calling toString() automatically calls the required method. Without any reflection from your part.

You might want to have a look at Apache Commons Lang, Especially ToStringBuilder.reflectionToString(). Even if you don't want to introduce a dependency just for a toString(), it's open source so you can have a look at the implementation.
method.invoke accept the Wrapper types instead of the primivtes types.

Perhaps there is something I don't understand in your question but for primitive, you can do ""+primitive to cast it to a String.

What you are trying to do doesn't really make sense.... when your function is called with a primitive argument (e.g. an int) then it will automatically get boxed into an Integer. So you might as well just call obj.toString() on it.....
However if you really want to do something special with primitives, you might want to do something like the following using method overloading:
private String toString(Object obj){
return obj.toString();
}
private String toString(int intValue) {
// code to return string for the primitive int case, assuming it is different
}
// more overloads for other primitive argument types as needed.....
This can be a very useful technique for dealing with primitives in some cases.

The immediate problem in your code is that obj is an Object, and therefore cannot be an instance of a primitive type. (It must be an instance of the corresponding wrapper type). The primClass.cast(obj) call must fail for any primitive type class.
But if you simply want to turn a primitive wrapper instance to a String, just call the instance's toString() method.

String.valueOf(arg) will do it nicely too.

Related

In Java, how to get all possible return types?

In Java, a method could be defined as following:
Object m(boolean b) {
if (b) {
return "123";
} else {
return new Integer(123);
}
}
In this case, the return value of m could be either String or Integer in runtime. So is there any way to get all possible run time return types of a method in static time?
For this particular method, yes. Just call it with true and false and check the return value with getClass(). For a general case, no.
Generally you wouldn't need to either. Thanks to Java's strong typing and generics, the type of the return value should never be a huge surprise.
Returning multiple different types as shown in your example should be avoided, and in cases where it's useful/necessary (such as factory pattern) it should be irrelevant to the caller.
If you know the implementation of the method, yes. You know all the types it could return because you can read the code and tell for yourself what they are.
But, programmatically? For any method, in general? No, you can't do that, not at run-time. This is why it's very important to write good, sensical method signatures with meaningful return-types. Returning Object is seldom the best idea. When you say that your method returns Object, the contract of that method is that literally anything is allowed to come out of it. There's nothing wrong with that, but that's the most specific thing you can say about a method if all you know is its signature.

Java Reflection for creating new objects

Is there a way to create primitive data type variables use Java Reflection?
For example,
public Object createObj(String type, String value){
if(type.compareTo("char") == 0)
//return a char
else if(type.compareTo("int") == 0)
//return an int
....
}
The common idiom I see here is to use Class.forName().
public static Object makeNew(String type) throws Exception {
Class clazz = Class.forName(type);
return clazz.newInstance();
}
For int, char you have to use the names of their respective class-types, you can't actually make a primitive. "java.lang.Integer", "java.lang.Character", etc. respectively. You'll need to check those specially if you want to pass in "int", "char", etc.
Adding a "value" as a string is much harder. Most classes will not have a way of changing a string into an initial state. You'll definitely have to special case the primitives to provide an initial value. Overall, I think this is not a great way to approach whatever problem you are tying to solve.
So you mention in your comment about using setter methods. One problem is how do you determine which setter do you call? If you pass a parameter of "10", for a JButton, is that the setAlignmentX, setAlignmentY, or the setText method?
At this point you have to go whole hog on it.
<class>
<name>javax.swing.JButton</name>
<set><method>setAlignmentX</method><value>10</value></set>
</class>
Now you have the problem that some setters take other classes as parameters. And some classes are immutable (Integer and Character are), they have no setters at all, you'll have to call a ctor.
You're basically getting into serialization here (which is a very hard problem). Take a look at XmlEncoder and XmlDecoder, they do something close to what you want. https://docs.oracle.com/javase/8/docs/api/java/beans/XMLEncoder.html

Efficient way to convert unknown objects to appropriate Method.invoke arguments?

I'm writing a reflection-based RPC service that gets arguments passed in via a variety of mechanisms. Sometimes the arguments correctly match the parameter type, sometimes they're always strings, and sometimes they're wrapped up in dynamically typed "scripty" objects that need the appropriate value extracted out.
Before I can call method.invoke, I need to build the argument list, something like this:
Object a[] = new Object[method.parameterClasses.length];
for (int i = 0; i < a.length; ++i)
{
a[i] = prepare(method.parameterClasses[i], rpc.arguments[i]);
}
The "prepare" method looks something like:
Object prepare(Class clazz, Object o)
{
if (o == null) return null;
if (clazz == o.getClass()) return o;
if (clazz == String.class) return o.toString();
// skip a bunch of stuff for converting strings to dates and whatnot
// skip a bunch of stuff for converting dynamic types
// final attempts:
try
{
return clazz.cast(o);
}
catch (Exception e)
{
return o; // I give up. Try the invoke and hope for the best!
}
}
During unit testing, I was recently rather surprised to discover that a method passed a boxed Integer that expected a primitive long was actually failing the cast and falling through the bottom, and then being properly converted by something during the invoke(). I'd assumed the call to "cast" would do the trick. Is there any way to explicitly perform and check the argument conversion done normally by invoke?
Lacking that, I thought about putting in explicit checks for numeric types, but the number of permutations seemed out of hand. When I add support for extracting numbers from the script dynamic types and converting strings, it gets even worse. I envision a bunch of conditional typechecks for each possible numeric target class, with Integer.decode, Long.decode etc for the String arguments, Short.decode, and Number.intValue, Number.longValue, etc. for Numbers.
Is there any better way to do this whole thing? It seemed like a good approach at first, but it's getting pretty yucky.
It is indeed surprising, but that is the current behavior. See bug 6456930.
In terms of a better way to approach the problem, at its core, no you will have to define all of those rules. There are better (more maintainable) patterns that a series of if's, though. For starters, I'd have some strategy objects that can be invoked for one side of those objects (probably the class side) so that you look up the appropriate object (say from a Map) based on the class, and then you can limit your conversions to one side (each object would be concerned about how to get things into that particular class). That way when there is a new kind of class conversion that you need to support, you can write an object for it, test it separately and just plug it into the map without changing further code.
There's really not a better way. There are an infinite number of potential conversions, but only a tiny number that really make sense. Rather than trying to give clients complete freedom, I recommend specifying a contract for type coercion.
As a starting point, check out the type conversion rules used by the JSP Expression Language. They are quite powerful, and allow many types of conversions to take place, but they are also well-defined, easy to remember—and possible to implement.
There are at least a few shortcuts you can take to simplify your code:
If the parameter is an instance of java.lang.Number and the argument type is either byte, short, int, long, float or double (either as primitive, or as wrapper class), you can use the methods in Number like byteValue(), shortValue(), etc to convert the parameter.
If the parameter is an instance of java.lang.String and the argument type is one of the above mentioned, you can use the static valueOf(String) method in the respective class for conversion.
Converting further, and perhaps even proprietary types would of course need more work. If it's really necessary and your prepare method is getting to large, you should perhaps consider abstracting the conversion behind an interface and allowing pluggable conversion providers to be dynamically added to the application?

Calling closest fitting method

As part of developing a small ScriptEngine, I reflectively call java methods. A call by the script engine gives me the object the method name and an array of arguments. To call the method I tried to resolve it with a call to Class.getMethod(name, argument types).
This however only works when the classes of the arguments and the classes expected by the Method are the same.
Object o1 = new Object();
Object out = System.out;
//Works as System.out.println(Object) is defined
Method ms = out.getClass().getMethod("println",o1.getClass());
Object o2 = new Integer(4);
//Does not work as System.out.println(Integer) is not defined
Method mo = out.getClass().getMethod("println",o2.getClass());
I would like to know if there is a "simple" way to get the right method, if possible with the closest fit for the argument types, or if I have to implement this myself.
Closest fit would be:
Object o1 = new Integer(1);
Object o2 = new String("");
getMethod(name, o1.getClass())//println(Object)
getMethod(name, o2.getClass())//println(String)
Update:
To clarify what I need:
The Script Engine is a small project I write in my free time so there are no strikt rules I have to follow. So I thought that selecting methods called from the Engine the same way the java compiler selects methods at compile time only with the dynamic type and not the static type of the Object would work.(with or without autoboxing)
This is what I first hoped that the Class.getMethod() would solve. But the Class.getMethod() requires the exact same Classes as argument types as the Method declares, using a subclass will result in a no such method Exception. This may happen for good reasons, but makes the method useless for me, as I don't know in advance which argument types would fit.
An alternate would be to call Class.getMethods() and iterate through the returned array and try to find a fitting method. This would however be complicated if I don't just want to take the first "good" method which I come across, so I hoped that there would be an existing solution which at least handles:
closest fit: If arg.getClass() ==
subclass and methods m(Superclass),
m(Subclass) then call m(Subclass)
variable arguments:
System.out.printf(String ,String...)
Support for autoboxing would be nice, too.
If a call cannot be resolved it may throw an exception ( ma(String,Object), ma(Object, String), args= String,String)
(If you made it till here, thanks for taking the time to read it:-))
As others have pointed out there is no standard method that does this, so you are going to have to implement your own overload resolution algorithm.
It would probably make sense to follow javac's overload resolution rules as closely as possible:
http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#292575
You can probably ignore generics for a dynamically-typed scripting language, but you might still benefit from the bridge methods that the compiler generates automatically.
Some pitfalls to watch out for:
Class.isAssignableFrom does not know about automatic widening primitive conversions, because these are syntactic sugar implemented in the compiler; They do not occur in the VM or class hierarchy. e.g. int.class.isAssignableFrom(short.class) returns false.
Similarly Class.isAssignableFrom does not know about auto-boxing. Integer.class.isAssignableFrom(int.class) returns false.
Class.isInstance and Class.cast take an Object as an argument; You cannot pass primitive values to them. They also return an Object, so they cannot be used for unboxing ((int) new Integer(42) is legal in Java source but int.class.cast(new Integer(42)) throws an exception.)
I would suggest that you use getMethods(). It returns an array of all public methods (Method[]).
The most important thing here is:
"If the class declares multiple public member methods with the same parameter types, they are all included in the returned array."
What you will then need to do is to use the results in this array to determine which one of them (if any) are the closest match. Since what the closest match should be depends very much on your requirements and specific application, it does make sense to code it yourself.
Sample code illustrating one approach of how you might go about doing this:
public Method getMethod(String methodName, Class<?> clasz)
{
try
{
Method[] methods = clasz.getMethods();
for (Method method : methods)
{
if (methodName.equals(method.getName()))
{
Class<?>[] params = method.getParameterTypes();
if (params.length == 1)
{
Class<?> param = params[0];
if ((param == int.class) || (param == float.class) || (param == float.class))
{
//method.invoke(object, value);
return method;
}
else if (param.isAssignableFrom(Number.class))
{
return method;
}
//else if (...)
//{
// ...
//}
}
}
}
}
catch (Exception e)
{
//some handling
}
return null;
}
In this example, the getMethod(String, Class<?>) method will return a method that with only one parameter which is an int, float, double, or a superclass of Number.
This is a rudimentary implementation - It returns the first method that fits the bill. You would need to extend it to create a list of all methods that match, and then sort them according to some sort of criteria, and return the best matching method.
You can then take it even further by creating the more general getMethod(String, Class<?>) method, to handle more of the possible "close match" scenarios, and possibly even more than one paramter
HTH
Edit: As #finnw has pointed out, be careful when using Class#isAssignableFrom(Class<?> cls), due to its limitations, as I have in my sample code, testing the primitives separately from the Number objects.
AFAIK, there is no simple way to do this kind of thing. Certainly, there's nothing in the standard Java class libraries to do this.
The problem is that there is no single "right" answer. You need to consider all of your use-cases, decide what the "right method" should be and implement your reflection code accordingly.

Why is this generic method unsafe?

The following method generates a warning, but it looks safe to me. I'm sure the problem is with me:
public <S extends CharSequence> S foo(S s) {
return (S) new StringBuilder(s);
}
It looks like this will always return the argument s. Can anyone show an example that would cause this method to throw an exception?
Edit: I'm not particularly interested in the question of whether generics are necessary here. Rather, I'm looking for a demonstration of how this method is unsafe.
It's unsafe because while StringBuilder is a CharSequence, it isn't necessarily of type S (in fact, it almost certainly won't be). You can see this failing just by passing a String into your method. This will construct a StringBuilder using your String as an argument, and then try to cast your StringBuilder to String (which will fail).
There's probably no need to use generics here at all, this should work fine:
public CharSequence foo(CharSequence s) {
return new StringBuilder(s);
}
For example this will compile:
String a = foo("ss");
but it will fail at runtime:
ClassCastException: java.lang.StringBuilder cannot be cast to java.lang.String
since foo returns S, the type of your input parameter (String in this case).
I think that you don't need to use generics here (as skaffman said in his answer):
public StringBuilder foo(CharSequence s) {
return new StringBuilder(s);
}
foo("test");
is enough to make java try to cast a StringBuilder in a String.
Your code is guaranteed o be wrong, can you explain what you're trying to achieve plase ?
The unsafety here lies not within the method itself (though it has its problems, too) but at the call site. The use of S for the input argument's type as well as for the return value tells the compiler, that whatever the type of object may be that is passed to the function, the result has the same type (or a derived type, actually).
Thus, the compiler is allowed to assume, that in the call
foo("hello, world")
the result will be a java.lang.String, while in the call
foo(new StringBuffer("hello, world"))
the result will be a StringBuffer, and so on. In both cases, however, your method does not return what it was supposed to return, namely, an object of the same type as the input argument. Instead, a StringBuilder is returned.
Actually, the only kind of input argument your method will work with is a StringBuilder, anything else will be doomed to crash with a ClassCastException sooner or later, as the compiler might (and often does) insert (hidden) casts at the call sites.
And of course, as others have already pointed out, the use of generics is not really necessary here, anyway.
The return type of your method code is ALWAYS a StringBuilder.
That is because the declared type of the expression 'new StringBuilder(x)' is ALWAYS a StringBuilder, whatever the X.
It is TOTALLY pointless to try and cast this to anything. The "S" information is part of the erasure, which exists only at compile-time and is erased by the time the program runs, that is, run-time. (Casting is a run-time thing exclusively, and casting something to some type/class whose identity has been erased a run-time, is indeed totally pointless.)
my Java is rusty, but would this method not throw whatever exceptions
new StringBuilder(s)
can throw?

Categories

Resources