reflection type checking? - java

I'd like to find a way to dynamically check if string is parse-able into a given type.
in other words,
public boolean canBeParsed(String type, String val) {
// use reflect to check if val can be parsed into type
}
clearly, I'd like to be able check different types with different values..
types will be strings like : Java.lang.Integer
---------- addition -------------
so for example, if I call this function,
canBeParsed("Java.lang.Integer", "1"); //returns true
canBeParsed("Java.lang.Integer", "HelloWorld"); //returns false
canBeParsed("Java.lang.String", "HelloWorld"); //returns true
canBeParsed("Java.lang.Boolean", "false"); // returns true
canBeParsed("Java.lang.Boolean", "HelloWorld"); //returns false

This method works with classes which declare a static valueOf method. Any class without this will return false. Several exceptions have been omitted to keep the code short.
Class<?> cls = Class.forName(type);
//Get a converter method, String to type
//Requires static method valueOf
Method converter;
try{
converter = cls.getDeclaredMethod("valueOf",new Class[]{String.class});
}catch(NoSuchMethodError ex){
//No conversion method found
return false;
}
if(!Modifier.isStatic(converter.getModifiers()){
//the method has to be static in order to be called by us
return false;
}
if(!cls.isAssignableFrom(converter.getReturnType())
//The conversion method has the wrong return type
return false;
try{
//try to parse the value
Object o = converter.invoke(null,new Object[]{value};
if( o == null)return false;//false if method returned null
else return true;//success
}catch(Exception ex)
{
//could not parse value
return false;
}
The valueOf(String) method is present in the wrapper classes Short,Long,Integer,Float,Double,Boolean so it supports these and any other class which has this method.

A dynamic type check is something different from what you are asking. With a dynamic check you check if an obect is an instance of a specific type (basically sametype or narrower type will be allowed) and you can do it with the instanceof operator. But this involves the object hierarchy and not the "can be converted to" concept that you would like to have. You can try with string instanceof Integer but this will be ALWAYS false.
In your situation you want to check if a string rapresents an integer number and you should do it in a different way:
try {
int number = Integer.parseInt(string);
}
catch (NumberFormatException e) {
System.out.println("String is not an integer string!");
}
Otherwise you could define a regex for every type and check what the string contains through it:
if (string.matches("[1-9][0-9]*"))
...
In anycase, since a String is just a string type and nothing else, the RTTI won't help you here. The string itself is orthogonal with every other type (int, float, whatever) also if it rapresents the textual version of another type.
A solution can be found if you can modify the source string types, in this case you could define for example an
class IntString extends String {
IntString(int i) {
super(Integer.toString(i));
}
}
then you could check if string instanceof IntString but this would work only if the strings are built with their specific type eg String s = new IntString(20).

Your easiest solution is probably a switch statement, with one case for each type that you want to support.
public boolean canBeParsed(String type, String val)
{
switch(type) {
case "Java.lang.Integer" : return(tryParseInteger(val) != null);
case ...
}
public static Integer tryParseInteger(String text) {
try {
return new Integer(text);
} catch (NumberFormatException e) {
return null;
}
}
In C# this would be easier, as there is an actual TryParse() method for each numeric type, and it's not necessary to catch an exception to test it.

Related

How to avoid returning an object when the class of the returned value is not evident at function call?

For a project I am working on, I have to retrieve some entries from a NoSQL database. The values may either be Strings or Doubles, however, at the time of calling the method that retrieves these values, I do not know what type of value the field contains.
For the sake of argument here is a minimal working example, which is of course oversimplified:
public class ReturnType {
public static void main(String[] args) {
String s = "This is a string.";
double d = 23.5;
getValue(s);
getValue(d);
}
private static Object getValue(Object obj) {
return obj;
}
}
I have thought about checking the class of the object that is returned by the function and casting the returned object to that class:
if (getValue(s).getClass() == String.class){
String result = s;
} else if (getValue(s).getClass() == double.class)
{
Double result = d;
}
However, I do not like this solution at all, as I have to hardcode every possible return type into an if or case statement.
I have also thought about creating an additional method that checks the class before calling the method retrieving the value and using different methods with different return types, depending on the result of that. But this seems just like the same approach, albeit implemented differently.
What would be a best practice solution to this problem?

Can method return more than one type

I am new to Java and trying to understand the below code:
int someMethod() {
return (true ? null : 0);
}
The method's return type is int, but it can return both null and int, is this correct behavior in Java? Can a Java method return more than one type? This may sound silly for those who are experienced, but I have just took my first step in Java.
A method cannot return more than one type.
The signature of a method contains the return type or void if the method doesn't return anything. Since it must be defined in the method signature, you must return something of that type.
The code
return (true ? null : 0);
is a shorthand if-else statement, or conditional ternary expression, and can be rewritten to this:
if (true) {
return null;
}
else {
return 0;
}
The above code, however, won't compile since one cannot return null if the return type is the primitive type int. The above code will compile, because the JVM will try to convert null to an int, due to auto-unboxing. At runtime, it will throw a NullPointerException, as pointed out by Eran.
In order to 'return multiple types', you could do the following:
public class BooleanOrInt {
private boolean isInteger; // Whether value is boolean or int
private boolean b;
private int i;
public BooleanOrInt(boolean b) {
this.b = b;
this.isInteger = false;
}
public BooleanOrInt(int i) {
this.i = i;
this.isInteger = true;
}
public boolean isInteger() {
return this.isInteger;
}
}
And then your code should be as follows:
BooleanOrInt methodOfA() {
if (someCondition) {
return new BooleanOrInt(theBooleanYouWant);
}
else {
return new BooleanOrInt(theIntegerYouWant);
}
}
It's a conditional ternary expression, which means the method returns one of the two values following the ?, depending on the evaluation of the condition he appears prior to ? (which in your case always returns true).
The type of the expression (true ? null : 0) is Integer, since that's the common type for null and 0.
Your code will throw a NullPointerException, since when you return a null Integer in a method whose return type is int, the JVM attempts to convert the Integer to int and fails.
In order to fix this code, you'll have to change the return type to Integer (which is the reference type that serves as a wrapper for the int primitive type) :
Integer methodOfA()
{
return (true ? null : 0);
}
Java method cannot return more than one type in the form you are suggesting. However, it can return any number of sub-types. In your case, int is a primitive type and it cannot have sub-types. Here you cannot return null since null can only be returned by methods whose return type is an object. For primitives you have to specify some values (0 in your case).

Can i use a string variable as a datatype to create other variables in java

I use reflection to invoke a method as:
method.invoke(someObject, null);
The problem is, I want to use the value that this method returns without having it's data type known before hand. I have the knowledge of the data type in a string variable, say
String type = "String";
Is it possible to do something equivalent of this-
type variable = method.invoke(someObject, null)
Check the Object type with instanceof.
Object o = method.invoke(...);
if(o instanceof Integer) {
// Integer logic...
}
if(o instanceof YourType) {
// YourType logic...
}
// and so on
Maybe something like this could work for you:
if(type.equals("String"){
String o = (String) returnedObject;
} else if(type.equals("Integer")){
Integer o = (Integer) returnedObject;
}
But I recommend not going down this road. There has to be some better way to achieve your desired result.

Java how to check if a string value is a type of given Class<?>

Alright this is kind of a complicated question and I'm completely lost.
Assume you have a string, and a generic class. Like this.
String string;
Class<?> clazz;
How would you check to see if the String represented a value that the class could equal.
For example lets say that:
String string = "true";
Class<?> clazz = Boolean.class;
How would I check and see that the string "true" is in fact a boolean?
Here is another example. Lets say that:
String string = "true";
Class<?> clazz = Integer.class;
How would I check and see that the string "true" is not an Integer?
Given that you want this only for Wrapper Types, you can use some reflection hack here (Exception handling for irrelevant code is ignored here for brevity):
String string = "ABC";
Class<?> clazz = Integer.class;
Method method = clazz.getDeclaredMethod("valueOf", String.class);
if (method != null) {
try {
Object obj = method.invoke(null, string);
System.out.println("Success : " + obj);
} catch (InvocationTargetException ex) {
System.out.println("Failure : " + string + " is not of type " +
clazz.getName());
}
}
I'm taking into account the fact that, every wrapper class has a static valueOf method that takes a parameter of type String, and returns the value of that wrapper type. And throws an exception, if the parameter is not convertible to the respective wrapper type.
So, in above case, if an exception is thrown, the string value is not of clazz type.
P.S.: Note that for Boolean.class, any string that is not "true" will be treated as false.
I'm assuming you are implementing some sort of Specification/Protocol or similar.
Look at the Spec.
Define a Grammar of valid input
Parse that grammar.
This is similar to what Programming Languages are doing with literals.
In javascript you could eval() the string. In Java you don't have such means. You'll have to implement your own heuristics for this check.
The one thing you can do however, is try to parse the string with the given class. Like:
Iteger.parseInt(stringValue);
If the parse succeeds, then the string can be used as a value for that type. If it fails, then you get an exception. Implement these checks and then deduct some conclusion.
I'm not able to test this solution right now, but why not something like this? If you can enumerate all of the possible classes yourself, just create some switch statements on the class.
boolean isStringClass (Class clazz, String string) {
try {
if (Integer.class == clazz) {
Integer.valueOf(string);
} else if (Boolean.class = clazz) {
Boolean.valueOf(string);
} [...etc]
} catch (Exception e) {
return false;
}
return true;
}
Of course you will need to know all of the possible classes, and you will need to know of a method that belongs to that class that is able to parse a String and return its type. For the primitive wrappers that would be valueOf.
If you plan on only converting wrappers, Rohit's solution would be a better choice. However, if you're not doing that and you're unable to add a valueOf method to this new Class, this may be your only option.
I would consider using the JavaBeans PropertyEditor mechanism for this.
#Test
public void testIsOfType() {
assertFalse(test("nope", Integer.class));
assertFalse(test("nope", Boolean.class));
assertTrue(test("1", Integer.class));
assertTrue(test("true", Boolean.class));
}
boolean test(String str, Class<?> clazz) {
PropertyEditor propertyEditor = PropertyEditorManager.findEditor(clazz);
if (propertyEditor != null) {
try {
propertyEditor.setAsText(str);
return true;
} catch (Exception ex) {}
}
return false;
}
This avoids the need for explicit reflection, and if you ever decided you needed to test classes other than the primitive wrappers you could register a new editor with PropertyEditorManager.registerEditor().
Unfortunately this still has the problem that Rohit's solution has in that test("1", Number.class) will fail.

How can I know if Object is String type object?

I have to know if Object is String or any other class type, how can I do it? Currently I do it like below, but its not very good coding.
try {
String myString = (String) object;
// do stuff here
} catch(Exception e) {
// it wasn't string, so just continue
}
object instanceof Type
is true if the object is a Type or a subclass of Type
object.getClass().equals(Type.class)
is true only if the object is a Type
Use the instanceof syntax.
Like so:
Object foo = "";
if( foo instanceof String ) {
// do something String related to foo
}
Guard your cast with instanceof
String myString;
if (object instanceof String) {
myString = (String) object;
}
From JDK 14+ which includes JEP 305 we can do Pattern Matching for instanceof
Patterns basically test that a value has a certain type, and can extract information from the value when it has the matching type.
Before Java 14
if (obj instanceof String) {
String str = (String) obj; // need to declare and cast again the object
.. str.contains(..) ..
}else{
str = ....
}
Java 14 enhancements
if (!(obj instanceof String str)) {
.. str.contains(..) .. // no need to declare str object again with casting
} else {
.. str....
}
We can also combine the type check and other conditions together
if (obj instanceof String str && str.length() > 4) {.. str.contains(..) ..}
The use of pattern matching in instanceof should reduce the overall number of explicit casts in Java programs.
PS: instanceOf will only match when the object is not null, then only it can be assigned to str.
Either use instanceof or method Class.isAssignableFrom(Class<?> cls).
javamonkey79 is right. But don't forget what you might want to do (e.g. try something else or notify someone) if object is not an instance of String.
String myString;
if (object instanceof String) {
myString = (String) object;
} else {
// do something else
}
BTW: If you use ClassCastException instead of Exception in your code above, you can be sure that you will catch the exception caused by casting object to String. And not any other exceptions caused by other code (e.g. NullPointerExceptions).
Its possible you don't need to know depending on what you are doing with it.
String myString = object.toString();
or if object can be null
String myString = String.valueOf(object);
Could you not use typeof(object) to compare against

Categories

Resources