views:

54

answers:

2

I have the following C# helper class which retrieves a Json String from a remote server and casts it to the type I need.

public class JsonHelper
{
    private JavaScriptSerializer serializer = new JavaScriptSerializer();

    public T GetValue<T>(string methodName, object param) where T : IConvertible
    {
        string result = GetJsonString(methodName, param);
        return (T)Convert.ChangeType(obj, typeof(T));
    }

    public T GetObject<T>(string methodName, object param) where T : new()
    {
        var result = GetValue<string>(methodName, param);
        return serializer.Deserialize<T>(result);
    }
}

-

// Usage:
bool value1 = GetValue<bool>(methodName, param);
int value2 = GetValue<int>(methodName, param);
double value3 = GetValue<double>(methodName, param);
User user = GetObject<User>(methodName, param);
List<User> users = GetObject<List<User>>(methodName, param);

Now I want to have the same functionality in a java programm. There are two points where I get stuck at the moment:

  • Is this method call correct?

     public <T> T SendJsonPrimitiveRequest(String methodName, Object param)
        { 
            return null;
        }
    

And how do I restrict this generic method to only accept type parameters that can be casted from string.

  • GetValue should be used for retrieving int, double, bool and string values which works great in C# by using Convert.ChangeType(...); Is this possible for Java or do I have to write methods like GetBool(), GetInt(), ...?
+3  A: 

Unfortunately, Java doesn't have a built-in interface to describe conversion from a string. The closest is that some objects take a String in the constructor, or have a valueOf(String) static method. As there is no interface to declare this feature, it's not going to be possible to use generics to restrict the type to objects that can be constructed from a string.

You can use generics with boxed types to provide a single GetValue method, but it requires also that you pass in the corresponding class of the type you want to retrieve, e.g.

  T <T> getValue(String methodName, Object param, Class<T> type)

Not very pretty, and coupled with the lack of a nice way to generically construct objects from strings, it is probably simplest (and more efficient with no boxing required) to create separate getInt(), getBool() methods.

mdma
I used the non-generic approach with GetBool(), GetInt() ... Probably the best choise from a performance aspect. But the trick with an additional class parameter might become handy sometime.
SchlaWiener
+2  A: 

You'll need to give the Java method more help - because you won't be able to find out T from within the method normally. The usual way of doing this is to have an extra parameter:

public <T> T sendJsonPrimitiveRequest(String methodName,
                                      Object param,
                                      Class<T> clazz)

That way you'll be able to look at clazz at execution time in order to perform the appropriate conversion.

For other questions:

  • No, you can't restrict the type parameter to types which can be converted from strings (in either C# or Java)
  • You won't be able to use primitive types as type arguments, although you could use auto-unboxing:

    int x = sendJsonPrimitiveRequest("foo", param, Integer.class);
    
  • I don't know of a direct equivalent for Convert.ChangeType, although there may be some beans-related libraries which could help. In fact, Spring's conversion libraries may be useful to you in general.

I agree with mdma's overall verdict: it may well be simpler to special-case quite a few of your methods; Java generics are going to get in your way more than helping you, I suspect.

Jon Skeet