Using primitive types with ClassLoader - java

I've got a piece of code that is used to turn string representations delivered by Class.getCanonicalName() into their corresponding instances of Class. This usually can be done using ClassLoader.loadClass("className"). However, it fails on primitive types throwing a ClassNotFoundException. The only solution I came across was something like this:
private Class<?> stringToClass(String className) throws ClassNotFoundException {
if("int".equals(className)) {
return int.class;
} else if("short".equals(className)) {
return short.class;
} else if("long".equals(className)) {
return long.class;
} else if("float".equals(className)) {
return float.class;
} else if("double".equals(className)) {
return double.class;
} else if("boolean".equals(className)) {
return boolean.class;
}
return ClassLoader.getSystemClassLoader().loadClass(className);
}
That seems very nasty to me, so is there any clean approach for this?

Since you have an exception for this: Class.forName(int.class.getName()), I would say this is the way to go.
Checking Spring framework code http://static.springsource.org/spring/docs/3.1.x/javadoc-api/org/springframework/util/ClassUtils.html class, method resolvePrimitiveClassName , you will see that they do the same thing, but with a map ;). Source code: http://grepcode.com/file/repository.springsource.com/org.springframework/org.springframework.core/3.1.0/org/springframework/util/ClassUtils.java#ClassUtils.resolvePrimitiveClassName%28java.lang.String%29
Something like this:
private static final Map primitiveTypeNameMap = new HashMap(16);
// and populate like this
primitiveTypeNames.addAll(Arrays.asList(new Class[] {
boolean[].class, byte[].class, char[].class, double[].class,
float[].class, int[].class, long[].class, short[].class}));
for (Iterator it = primitiveTypeNames.iterator(); it.hasNext();) {
Class primitiveClass = (Class) it.next();
primitiveTypeNameMap.put(primitiveClass.getName(), primitiveClass);
}

Just to make life more fun, you'll also have trouble with arrays. This gets around the array problem:
private Pattern arrayPattern = Pattern.compile("([\\w\\.]*)\\[\\]");
public Class<?> getClassFor(String className) throws ClassNotFoundException {
Matcher m = arrayPattern.matcher(className);
if(m.find()) {
String elementName = m.group(1);
return Class.forName("[L" + elementName + ";"); // see below
}
return Class.forName(className);
}
The wrapping of the class name in [L(classname); - that I sourced here. I can't see a cleaner way of doing it, but I'm sure there must be one.
Of course an array of primitive types will need a further set of special-case logic...

Related

How to convert a String which looks like an Array into an actual Object Array?

Since
public static String requestMethodExecution(String objectName, String className, String methodName, Object...
params) {
return String.format("%s,%s,%s,%s", objectName, className, methodName, Arrays.toString(params));
}
returns a String, and if you would, for example, call the method like this:
requestMethodExecution("foo","bar","fooBar",2.0,3.0,"Hello");
You'd get a String like this: foo,bar,fooBar,[2.0,3.0,Hello]
I would love to iterate over that Array, but I can't since it is a String.
Reason behind this is this method: (I just started with reflection, so I do not know how else to do it)
public static Class[] getParameterType(String ...params) throws ClassNotFoundException {
Class[] paramTypes = new Class[params.length];
for(int i=0; i<params.length;i++){
Class paramClass = Class.forName(params[i]);
if (paramClass == Double.class) {
paramTypes[i] = (double.class);
} else if (paramClass == Integer.class) {
paramTypes[i] = (int.class);
} else {
paramTypes[i] = paramClass;
}
}
return paramTypes;
}
So far I have only come up with a very dirty way:
public static String[] getParams(String message){
int indexOfParamStart = message.indexOf("[");
int indexOfParamEnd = message.indexOf("]")+1;
String[] splitMessage = message.substring(indexOfParamStart, indexOfParamEnd).replaceAll("\\[", "")
.replaceAll("]", "").replaceAll(" ","").split(",");
return splitMessage;
}
Edit: Thanks for looking into this! Since some of you are asking what I am trying to achieve, here is a bit more explanation:
I want to implement a simple request/reply protocol which allows remote method invocation (and I do not want to use java RMI...)
So I listen for requests whose structure can be seen at the requestMethodExecution example.
There I have all the relevant information to call the Method upon my class, so to invoke the method I need it's arguments (and their value) and I do not know how to access them from the given String.
The others are easy with Class c = Class.forName(className); etc..
Edit#2:
My question is not about a simple regex, so why close it? The title already states a different subject, I am getting a bit salty here...
See this this question for using RegEx to extract the array body from the outer string (by the square brackets), and then you can simply use String.split(",") to split the array body into array items.

Java: how to convert from type A to type B?

I'm a java beginner and although I've looked for the topic both here and on Google I haven't found it. I'm sure it has to be there somewhere but it's me who doesn't know how to search. Anyway, here it is:
How can I write methods to convert from string/int/etc. to a class and vice-versa? I'd definitely like that my class conversion be automatic but I can live with less-than-perfect typecast. What I wouldn't be comfortable with is calling class("some string") or class.toString() for converting back and forth from string to class. I'd like it to be as seamless as possible. Here's an example:
I have a IsFound class that behaves like a boolean and I use it as a return type in a method; in the method body I return a string like "found" (instead of true). You may laugh at me for not using a Boolean but I want to play a little with a custom class/type. Here's some code
public class IsFound{
public boolean found; // field
public IsFound(String isFound_){
if(isFound_.equals("FOUND")){
found = true;
else found = false;
}
}
public String toString(){
if(found) return "found";
else return "not found";
}
}
This is the furthest I could get. I need the converter methods to/from string and for future references I'd like to know whether the converters are applicable for int, char or even other classes.
The solution to extend Boolean is only as a last resort, since I don't know what bloat I'm carrying along -- I want to create the class myself from 0.
EDIT:
I want to be able to use something like:
public IsFound parse(String substring_){
if(search(substring_, string) == true){
return FOUND; // or return "FOUND";
{
return NOTFOUND; // or return "NOT FOUND";
{
Currently it gives the error that can't convert from String to IsFound. I want to fill in this gap.
I'd also use an enum, here's one that gives you all of the functionality that is in your class.
public enum IsFound{
// each of these definitions are like calls to the IsFound constructor below
FOUND("found"),
NOT_FOUND("not found");
// string representation
private final String toString;
private IsFound(String isFound){
this.toString = isFound;
}
/**
* #Override
*/
public String toString(){
return toString;
}
// I think this is what you want. I'm not sure why you need this, but
// am including it as I think it gives you what you want. see example below
public static IsFound convert( String foundString ){
if( FOUND.toString.equals(foundString) ){
return FOUND;
}
else if( NOT_FOUND.toString.equals(foundString) ){
return NOT_FOUND;
}
else{
return null;
}
}
}
You can use this in the following ways:
private IsFound myFoundValue;
myFoundValue = IsFound.FOUND;
System.out.println(myFoundValue.toString()); // "found"
myFoundValue = IsFound.NOT_FOUND;
System.out.println(myFoundValue.toString()); // "not found"
switch( myFoundValue ){
case FOUND:
System.out.println("the value is FOUND");
break;
case NOT_FOUND:
System.out.println("the value is NOT_FOUND");
break;
default:
System.out.println("this should never happen");
break;
}
myFoundValue = IsFound.convert("found"); // IsFound.FOUND
System.out.println( myFoundValue.toString() ); // "found"
Your question smells like a classic XY Problem in that you appear to be barking up the wrong tree to find a solution to a problem that you may need to understand better. It's an anti-pattern to try to use Strings as a substitute for type, so you're far better off not doing this. For something like this, consider using either a boolean for a two-state type or an enum for a multi-state type.
e.g.,
public enum IsFound{
FOUND, NOT_FOUND, UNKNOWN
}
or...
public enum IsFound {
FOUND("Found"), NOT_FOUND("Not Found"), UNKNOWN("Unknown");
private String name;
private IsFound(String name) {
this.name = name;
}
public String getName() {
return name;
}
#Override
public String toString() {
return name;
}
}
in some other class.
private Map<Luggage, IsFound> lostLuggageMap = new HashMap<>();
The enum adds a compile-time type safety that Strings just don't have.
enums can have properties and behaviors (methods) that are extremely useful.
For conversion between "string" representations and POJO ( plain old java objects ), you may want to use serialization to / from a known text format such as JSON ( or XML ).
public class Search {
private boolean found;
// getters, setters, constructor
}
Serialization / Deserialization using Google's GSON library :
Search search = new Search();
search.setFound(true);
Gson gson = new Gson();
String json = gson.toJson(search);
// should output : { "found" : "true" }
// The opposite way , if json is a string equal to { "found" : "true" }
Gson gson = new Gson();
Search s = gson.fromJson(json, Search.class);
// s has found = true

Java reflection nested methods not modifying underlying object

I am taking in an array of methods and I want to chain them together to modify an object that I am working in.
For example I start with
"getStuff().get(1).get(3).setMoreStuff().put(stuff,6)"
I split it into an array called methods, and clean up the parameters inside each method and I try to modify this.
Object res = this;
String[] methods = targetString.split("\\.(?=\\D)");
for (String m : methods){
List<Object> params = new ArrayList<Object>();
List<Object> params = new ArrayList<Object>();
for (String p : m.split("\\(|,|\\)")) {
try {
if (p.indexOf(".") != -1){
double tempD = Double.parseDouble(p);
params.add(tempD);
} else {
int tempP = Integer.parseInt(p);
params.add(tempP);
}
} catch (Exception ex) { //not a number
params.add(p);
}
}
switch (params.size()) {
case 1:
res = res.getClass().getMethod(
params.get(0)
).invoke(res);
break;
case 2:
res = res.getClass().getMethod(
params.get(0),
params.get(1).getClass()
).invoke(res, params.get(1));
break;
case 3:
res = res.getClass().getMethod(
params.get(0),
params.get(1).getClass(),
params.get(2).getClass()
).invoke(res, params.get(1), params.get(2));
break;
}
in the end I notice that res has been modified the way that I expect. All the getters and setters are called correctly. But of course the underlying object "this" refers to has not been changed!
I guess I'm just calling the getters and setters of the copy I made in the first line!
now I can't just use
this.getClass().getMethod(...).invoke(...)
because I need to call the same getMethod on the object returned by this call.
To clarify:
Object res = this;
creates a "pointer" to this. So that when I call
res.getStuff().setStuff(foo)
this will also be modified.
but it seem that when I call
res = res.getStuff();
res = res.setStuff();
like I do in my loop,
this does not modify the underlying object this refers to?
Edit: Included more code as per request.
Edit2: added anther example, to clarify my problem.
Edit3: tried to add more code, its a bit hard to add a working program without including every class
Your general approach should be fine (although your approach to parameter conversion is somewhat ugly) - it's the specifics that are presumably causing you problems. Here's a short but complete program demonstrating calling methods and then seeing the difference afterwards:
import java.lang.reflect.*;
class Person {
private String name = "default";
public String getName() {
return name;
}
// Obviously this would normally take a parameter
public void setName() {
name = "name has been set";
}
}
class Test {
private Person person = new Person();
public Person getPerson() {
return person;
}
// Note that we're only declaring throws Exception for convenience
// here - diagnostic code only, *not* production code!
public void callMethods(String... methodNames) throws Exception {
Object res = this;
for (String methodName : methodNames) {
Method method = res.getClass().getMethod(methodName);
res = method.invoke(res);
}
}
public static void main(String[] args) throws Exception {
Test test = new Test();
test.callMethods("getPerson", "setName");
System.out.println(test.getPerson().getName());
}
}
The output is "name has been set" just as I'd expect. So see if you can simplify your code bit by bit, removing extra dependencies etc until you've got something similarly short but complete, but which doesn't work. I suspect you'll actually find the problem as you go.
Object does not change reference, its VALUE changes. So if you will call this.get("some key"), you will get value that the same value that you put using reflection.
Right?

Java generics and numeric types

I'd like to create a generic method which does effectively this:
class MyClass {
static <T extends Number> T sloppyParseNumber(String str) {
try {
return T.valueOf(str);
} catch (Exception e) {
return (T)0;
}
}
}
Now above does not compile for two reasons: there's no Number.valueOf() method and 0 can't be cast to T.
Example usage:
String value = "0.00000001";
System.out.println("Double: " + MyClass.<Double>sloppyParseNumber(value));
System.out.println("Float: " + MyClass.<Float>sloppyParseNumber(value));
double d = MyClass.sloppyParseNumber(value);
float f = MyClass.sloppyParseNumber(value);
Is implementing above generic method possible with Java? If yes, how? If no, what's a good alternative approach?
Edit: there seems to be a few possible duplicates, but I did not find one, which covers exactly this. I'm hoping there's some trick to pull, which would allow these two operations: parse string to a Number subclass, and return 0 value for a Number subclass.
I agree 100% with TofuBeer. But in case you wish to avoid verbosity for time sake, this should also do:
static <T extends Number> T sloppyParseNumber(String str,Class<T> clas) {
if (clas == null) throw new NullPointerException("clas is null");
try {
if(clas.equals(Integer.class)) {
return (T) Integer.valueOf(str);
}
else if(clas.equals(Double.class)) {
return (T) Double.valueOf(str);
}
//so on
catch(NumberFormatException|NullPointerException ex) {
// force call with valid arguments
return sloppyParseNumber("0", clas);
}
throw new IllegalArgumentException("Invalid clas " + clas);
}
But purely from T, you cannot get the type at runtime.
Java generics only provide compile time checks and the type information is pretty much thrown away after compilation. So the statement T.valueOf isn't possible in Java. The solution is to go the verbose way as already mentioned in the comments. Also, is there any reason why you want to do MyClass.<Double>sloppyParseNumber(value) but not MyClass.sloppyParseDouble(value) since you are anyway specifying the type at compile time?
Static methods are bound by the type, since the type is, at best, Number and Number doesn't have a valueOf method what you are after isn't going to work.
The easiest way is to just make a number of static methods like sloppyParseInt, sloppyParseFloat, etc...
You could do something like this, not sure I like it, and can probably be improved on:
public class Main
{
private static final Map<Class<? extends Number>, NumberConverter> CONVERTERS;
static
{
CONVERTERS = new HashMap<>();
CONVERTERS.put(Integer.class, new IntegerConverter());
}
public static void main(String[] args)
{
Number valueA;
Number valueB;
valueA = CONVERTERS.get(Integer.class).convert("42");
valueB = CONVERTERS.get(Integer.class).convert("Hello, World!");
System.out.println(valueA);
System.out.println(valueB);
}
}
interface NumberConverter<T extends Number>
{
T convert(String str);
}
class IntegerConverter
implements NumberConverter<Integer>
{
#Override
public Integer convert(String str)
{
try
{
return Integer.valueOf(str);
}
catch (NumberFormatException ex)
{
return 0;
}
}
}
So, I decided on an alternative approach:
static String trimTo0(String str) {
if (str == null) return "0";
str = str.trim();
if (str.isEmpty()) return "0";
return str;
}
Usage:
String value = null;
System.out println("Double value: " + Double.parseDouble(trimTo0(value)));
Note that this is more limited than the method in the question, this does not convert invalid, non-numeric strings to "0". Doing that fully would require two separate methods, one supporting decimal point and another just supporting integers.
You can try this:
private <T> T convertToType(Class<T> clazz,String str) throws Exception {
return clazz.getConstructor(String.class).newInstance(str);
}
Here you need to consider that the Type must have a constructor with a String parameter.

Recursively print an objects details

How do I print the content of an object recursively?
You can print it recursively by overriding toString in all your classes.
If you want to have a method like printObjectRecursively(Object o) you need to dive into reflection, fetch the fields, print their name and content recursively using printObjectRecursively(someField).
Example:
public class Test {
public static void main(String[] args) {
A a = new A();
System.out.println(a);
}
}
class A {
int i = 5;
B obj = new B();
String str = "hello";
public String toString() {
return String.format("A: [i: %d, obj: %s, str: %s]", i, obj, str);
}
}
class B {
int j = 17;
public String toString() {
return String.format("B: [j: %d]", j);
}
}
Prints:
A: [i: 5, obj: B: [j: 17], str: hello]
A reflection-based recursive print method could be written something like this
private static final List LEAVES = Arrays.asList(
Boolean.class, Character.class, Byte.class, Short.class,
Integer.class, Long.class, Float.class, Double.class, Void.class,
String.class);
public static String toStringRecursive(Object o) throws Exception {
if (o == null)
return "null";
if (LEAVES.contains(o.getClass()))
return o.toString();
StringBuilder sb = new StringBuilder();
sb.append(o.getClass().getSimpleName()).append(": [");
for (Field f : o.getClass().getDeclaredFields()) {
if (Modifier.isStatic(f.getModifiers()))
continue;
f.setAccessible(true);
sb.append(f.getName()).append(": ");
sb.append(toStringRecursive(f.get(o))).append(" ");
}
sb.append("]");
return sb.toString();
}
You can use:
ToStringBuilder.reflectionToString(this);
Apache Common Lang contains ToStringBuilder class. You can define different style with ToStringStyle object.
I've had great success doing this on a casual basis using XStream to dump JSON representations of objects. It recurses down objects and just seems to do what you want it to do most of the time. And it's super lightweight. Example:
private static final XStream jsonXStream =
new XStream(new JsonHierarchicalStreamDriver());
public static String toDebugString(Object object) {
return jsonXStream.toXML(object);
// ignore "toXML" name, it's going to be JSON.
}
You should implement the toString method for your classes - it will print the information about the class members - usually using their toString methods. |Then you jut iterate through the collection and call toString of each item
Do you really need print this informations out? Maybe watch during debbuging will be enough?
You are looking for something similar to PHP's var_dump, see if this question is of any help: What is the Java equivalent of PHP var_dump?
Also, have a look at reflection: http://java.sun.com/developer/technicalArticles/ALT/Reflection/
You can override the toString method.
Example:
class foo
{
int i,j;
String toString()
{
StringBuilder b=new StringBuilder();
return b.append(i).append(j).toString();
}
}
Use one of the serialization libraries like Jackson (JSON).
This dumps everything in plain text. If you use a Javascript capable editor to prettify the content, with a bit of luck, you might actually make some sense out of it.
If a lot of the objects are not serializable, you might end up with a lot of readable gibberish which will not help anything, unfortunately,
YMMV
In some cases it is easy to use Gson to print object. But sometimes gson does not work.
Here I just improve aioobe' answer for this case:
don't print printed objects (protect from infinite cycles)
print collections
don't go deeply on few basic types, like BigInteger
private static final Set<Object> looked = new HashSet<>();
private static final List LEAVES = Arrays.asList(
Boolean.class, Character.class, Byte.class, Short.class,
Integer.class, Long.class, Float.class, Double.class, Void.class,
String.class, java.math.BigInteger.class, java.math.BigDecimal.class);
public static void toStringRecursive(Object o, StringBuilder sb) throws Exception {
if (o == null) {
sb.append("null");
return;
}
if (looked.contains(o)) return;
looked.add(o);
if (LEAVES.contains(o.getClass())) {
sb.append(o);
return;
}
sb.append(o.getClass().getSimpleName()).append(": [");
if (o.getClass().isArray()) {
for (Object x : (Object[]) o) {
toStringRecursive(x, sb);
}
} else if (Iterable.class.isAssignableFrom(o.getClass())) {
for (Object x : (Iterable) o) {
toStringRecursive(x, sb);
}
} else if (Map.class.isAssignableFrom(o.getClass())) {
for (Object entry : ((Map)o).entrySet()) {
toStringRecursive(entry, sb);
}
} else {
for (Field f : o.getClass().getDeclaredFields()) {
if (Modifier.isStatic(f.getModifiers()))
continue;
f.setAccessible(true);
sb.append(f.getName()).append(": ");
toStringRecursive(f.get(o), sb);
sb.append(" ");
}
}
sb.append("]\n");
}

Categories