Reputation: 43013
I want to build a method that can convert a String value to a given Field
object data type through Java Reflection.
Here is my code:
String value = ...;
Class<? extends MyObject> clazz = getClazz();
Field f = clazz.getDeclaredField("fieldName");
boolean fieldIsAccessible = f.isAccessible();
if (!fieldIsAccessible) {
f.setAccessible(true);
}
f.getType().cast(value);
if (!fieldIsAccessible) {
f.setAccessible(false);
}
When I run this code at firs attempt, I receive this exception java.lang.ClassCastException
.
I want to convert value
to class java.math.BigDecimal
.
What is my code missing ?
EDIT: View the solution I came up with.
Upvotes: 6
Views: 12996
Reputation: 12397
You can create a small method using Supplier
and read the String using Scanner
:
private static <T> T getTokenValue(Supplier<T> supplier) {
return supplier.get();
}
String line = "12.0";
Scanner scanner = new Scanner(line);
double value = getTokenValue(scanner::nextDouble);
If we need to get the int, the call will be like,
getTokenValue(scanner::nextInt)
The code is a sample and can be improve using the vavr
dependency and Try clause that can throw custom exceptions with more generic code.
Try.ofSupplier(supplier).getOrElseThrow(new RuntimeException("Custiome message"));
varv has a lot of control logic that can be used to write more generic code.
Upvotes: 1
Reputation: 1669
I also gone through same scenario. Pasting code which i have written after doing some research. Guys please give suggestion if you feel anything wrong.
private <T extends Object> T convertStringToType(String value,Class type){
if( type.equals(Double.class)){
return (T) Double.valueOf(value);
}
else if(type.equals(Integer.class)){
if(value.contains(".")){
BigDecimal bigDecimal= new BigDecimal(value);
return (T) (Integer)bigDecimal.intValue();
}
return (T) Integer.valueOf(value);
}
else{ // add other type which you need
throw new Exception("Invalid type");
}
}
Upvotes: 1
Reputation: 20593
There is a Github project (MIT Licensed) called type-parser which does converting a string value to the desired data type
Here is the project description from GitHub
This is a light weight library that does nothing but parse a string to a given type. Supports all applicable java classes, such as Integer, File, Enum, Float etc., including generic Collection types/interfaces such as List, Set, Map, arrays and even custom made types. Also possible to register your own parsers.
Upvotes: 3
Reputation: 9
I found my answer in this thread: How to convert String object to Boolean Object? - you can parse strings to booleans using:
Boolean boolean1 = Boolean.valueOf("true");
boolean boolean2 = Boolean.parseBoolean("true");
Upvotes: 0
Reputation: 1176
Perhaps not answering the question how to do convert a String into a java type, as there is no generic way of doing it. But there is a library that can help you with this. See type-parser library. Here's how the above code sniped could look like:
String value = ...;
Class<? extends MyObject> clazz = getClazz();
Field f = clazz.getDeclaredField("fieldName");
boolean fieldIsAccessible = f.isAccessible();
if (!fieldIsAccessible) {
f.setAccessible(true);
}
TypeParser parser = TypeParser.newBuilder().build();
// parse value to whatever type f.getGenericType() returns
Object o = parser.parseType(value, f.getGenericType());
if (!fieldIsAccessible) {
f.setAccessible(false);
}
}
Upvotes: 1
Reputation: 43013
Here is the solution I came up with:
public static Object parse(String value, Class<?> clazz) throws NotSupportedException {
String canonClassName = clazz.getCanonicalName();
if (canonClassName.equalsIgnoreCase("java.math.BigDecimal")) {
return new BigDecimal(value);
}
// Add other supported classes here ...
throw new NotSupportedException("The class [" + canonClassName + "] is not supported.");
}
Upvotes: 0
Reputation: 26185
The Class cast method throws the ClassCastException if the object is not null and it not assignable to type T. There are only a few types of variable to which a String reference is assignable, String, Object, Serializable, Comparable, and CharSequence.
Many, but not all, classes have ways of producing an object instance based on a String. In some cases, including BigDecimal, there is a constructor that takes a String representation of the new object's value. You could use the Class getDeclaredConstructor method specifying a single String argument, to get the Constructor object for such a constructor, if there is one. However, there is some risk that you will not get a useful object without e.g. calling some setXXX methods, and this approach is limited to those classes that have the right form of constructor.
You are presumably trying to solve some higher level problem, possibly related to serialization and deserialization. That problem may be much more easily solvable than your current problem.
Upvotes: 1
Reputation: 5377
As maerics said, you cant just cast a String to a data type. Is it possible you mean "how do I parse a BigDecimal from a String", to which the answer is...
fieldName = new BigDecimal(value);
Upvotes: 1
Reputation: 7957
You could make this work for classes that have a string constructor like this:
f.getType().getConstructor( String.class ).newInstance( value );
Upvotes: 11
Reputation: 500257
In Java, there is no universal method for converting a String into an instance of an arbitrary class. Many classes simply don't support such a conversion. And there's no standard interface for those that do support it.
Your best bet is to look for a constructor that accepts a String as its sole argument. Of course, not every class provides such a constructor, and there's no guarantee that the semantics would be what you'd expect.
Upvotes: 3