I'm running into a problem with my program where given an object and an attribute name I want to return the method's return type.
public static Class<?> getAttributeType(Object object, String attributeName) {
try {
Method method = object.getClass().getMethod(
"get" + StringUtils.capitalize(attributeName));
return method.getReturnType();
} catch (Exception e) {
throw new RuntimeException("Unable to find the attribute:"
+ attributeName + " in class: "
+ object.getClass().getName());
}
}
This solution works great unless the return type of a method has a generic defined. For example if method prototype in question is List<Book> getBooks(), the code above would just return a List instead of a List<Book>. Is there any way for me to accomplish this? I can get the Generic type easily, I just don't know what to do with it once I have it.
Thanks in advance
To get the generic return type of a method, use the getGenericReturnType() method. This returns a Type, which you then test and down cast to a ParameterizedType which you can then query for the type parameters.
Not everything is possible via reflection, but is with a bytecode-library like ObjectWeb ASM.
The approach there is described in this article.
Related
< T > T foo(P p) {
...
}
I'll get different types of return from foo according to the parameter I inserted, which means T changes according to p.
Then I try to call this function and use its return result.
Class x = foo(p);
What should I write in substitute of Class here?
Suppose parameter is a enum type.
enum P {
XX,YY,ZZ
}
then the return type T is Xx, Yy, Zz respectively according to parameter.
Let me give the exact sample here.
public <T> List<T> getProperty(Property property) {
switch(property) {
case NAME: List<Name> names = new ArrayList<Name>();
names.add(this.name); return (List<T>) names;
case PHONE: return (List<T>) this.phones;
case EMAIL: return (List<T>) this.emails;
case ADDRESS: return (List<T>) this.addresses;
case NOTE: List<Note> notes = new ArrayList<Note>();
notes.add(this.note); return (List<T>) this.note;
default: return null;
}
}
public enum Property {
NAME, PHONE, EMAIL, ADDRESS, NOTE
}
public List<Entry> search(Property property, String s) {
if(this.isEmpty()) {
return null;
}
List<Entry> result = new ArrayList<Entry>();
for(Entry e : entries) {
if(e.getProperty(property) != null) {
for( **Object** p : e.getProperty(property)) { //What should I write instead of Object
if(p != null) {
if(p.containString(s)) { //there'll be errors if use Object. Need to know p's class.
result.add(e);
}
}
}
}
}
return this.nonDuplicatedResult(result);
}
I'm really not sure what you're asking. You haven't explained your use cases at all and haven't given us much code to look at. It's difficult to provide useful feedback from within the fog of obfuscation.
Generally speaking, if you want a method that returns a different object depending on the value of a supplied argument, then what you're probably talking about is a static factory method which can return any object that is a subtype of the method's return type. It is convenient to make such objects a part of an interface-based type system (eg. the static factories for the EnumSet class).
The use of an interface-based type system is actually necessary if you wish to return an enum, because enums cannot be part of a class hierarchy, but they can implement an interface that forms an interface-based type system.
Suppose parameter is a enum type.
enum P {
XX,YY,ZZ
}
then the return type T is Xx, Yy, Zz respectively according to parameter.
No it isn't. The return type is P. You're over-thinking this. The 'enum' case isn't a job for Generics at all.
Assuming you have an finite number of return types, you could just check through each one using instanceof to see if the returned value is of a certain type. So in this case Object would substitute class, then you could later cast it.
What is happening is basically with that method definition, what you are saying to the compiler is that your method will return whatever the parameter assignment declares itself to be. You can do that, but how your method is implemented will boil down to a compiler warning, as you can't actually ensure that you are generating the appropriate type - since you don't know it, it is never passed to the method, and erased at compile time.
More typically what you would do is:
<T extends P> T foo(T p) {
...
}
Now you get an object of the right type as a parameter, so you have some idea of what to return. That concept has little utility with enums, though.
Here is a real world example of where you could use the method definition you posed in your question:
public static <T> T generateProxy(Object realObject, Class<?>... interfaces) {
return (T) Proxy.newProxyInstance(realObject.getClass().getClassLoader(), interfaces, new SimpleInvocationHandler(realObject));
}
Of course such a method generates a compiler warning. Now, what you are saying here is that the caller will define a variable, and will be sure to pass in at least one interface of the type they define. If they don't, they will end up with a ClassCastException at runtime, but you avoid calling code that knows what it is doing from explicitly casting.
It is debatable if that is a good idea.
So the short answer is that you can define the Class to be whatever you want - the compiler will accept anything - but if the method doesn't return the correct type, you will get an exception at runtime, so it is all about how you implement the method. Rarely can a method be smart enough to return the right thing without the correct type as a parameter. And if you can't pass in an appropriate parameter declared with the generic type to the method, you will have to deal with a compiler warning in order to return anything (other than null).
One of my function getting Type variable. sometimes it can be java.util.List<Test$MyClass> or java.util.List<java.lang.String> so how can I identify them?
if (type instanceof List) {
}
Both are List type but different type. So that above code does not work.
I want to distinguish between the two list types.
my main issue is https://stackoverflow.com/questions/15596112/implement-jsondeserializer-more-than-one-in-gson-in-android
I am using deserializer for that..
public class Data implements JsonDeserializer<ArrayList<MyClass1>> {
public ArrayList<MyClass1> myList1 = new ArrayList<MyClass1>();
public ArrayList<MyClass2> myList2 = new ArrayList<MyClass2>();
#Override
public ArrayList<MyClass1> deserialize(JsonElement json, Type type,
JsonDeserializationContext context) throws JsonParseException {
Debug.e("", type.toString());
ArrayList<Layoutmap> data = new ArrayList<Layoutmap>();
try {
if (json.isJsonObject()) {
// my stuff
return data;
} else {
return new Gson().fromJson(json, type);
}
} catch (Exception e) {
e.printStackTrace();
}
return data;
}
}
above code works for public ArrayList<MyClass2> myList2 = new ArrayList<MyClass2>(); and myList2 is also i want to deserialize..
It's part of google Gson.
Yeah, the problem is that in Java an instance test against a type that is not reifiable is always an error.
For example:
if(o instance of List<E>)
where E is any type, will not compile.
You simply have to check that what's contained in the Lists are the same type, e.g.
if(list1.get(0) instance of String && list2.get(0) instance of String)
EDIT:
Not sure if there's a language barrier issue here (your question is hard to fully understand), but you should not need to make your method take an argument of type Type. As someone else mentioned, you have a bad design here. What you should be doing is simply defining how to deserialize each of your classes (if custom deserialization needs to be defined at all; that is, if the defaults won't work) and then get a list of those in the regular way with Gson.
I'm not super familiar with Gson, but it should be something like:
List<Class1> stuff = gson.fromJson(json, new TypeToken<List<Class1>>(){}.getType());
So, in other words, if each class has peculiarities that will make default deserialization not work, then there's no way (without a lot of gymnastics) to make a deserialize method work for every single type.
Also, don't combine all functionality into one. Getting an ArrayList<LayoutMap> should be separated from the functionality of deserializing each class.
try to use getClass() function on your type to find the class of an object on runtime.
for eg..
type.getClass().equals(java.lang.string)
You can just try something like :
for (int i=0; i<type.size(); ++i) {
if (type.get(i) instanceof String) {
// Do something here
}
}
This would check each element of the list and if its a string you could work on it.
Hopefully, type will be an instance of ParameterizedType. So you can use the method getActualTypeArguments().
I just find my solution .. I don't know it is better or not
I am comparing two Type variable like this...
if (type.toString().equalsIgnoreCase(
new TypeToken<List<Test.MyClass>>() {
}.getType().toString())) {
}else
{
}
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.
You could make this work for classes that have a string constructor like this:
f.getType().getConstructor( String.class ).newInstance( value );
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.
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.
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);
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.
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);
}
}
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");
}
}
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.
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.");
}
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");
For the primitive types: int, double, short, etc...
Given:
String typeName = "double";
How do I get double.class?
For a regular class we can do the following:
String typeName = "java.lang.Integer"
Class<?> clazz = Class.forName(typeName);
// Class.forName(typeName) returns Double.class
You can't do that. Check out the reflection documentation. Go to the "Class.forName()" section and there, you can find a note:
This cannot be used for primitive types.
One option might be to create a method that will recognize the primitive types and return the matching class (i.e. Integer.class, Double.class, etc...)
Rather than trying something clever, since there are only 8 primitives would it be so bad to write a switch/case statement, or hard code them in some other way such as a Map (suggested by Scorpion in comment below) ?
The Spring Framework takes this approach for its version of Class.forName.
Here's the code to find the class of a primitive type when all you know is it's name.
public class CheckPrimitve {
public static void main(String[] args) {
Sample s = new Sample();
try {
System.out.println(s.getClass().getField("sampleDouble").getType() == double.class); // returns true
System.out.println(s.getClass().getField("sampleDouble").getType().isPrimitive()); // returns true
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
}
}
class Sample {
public double sampleDouble;
public Sample() {
sampleDouble = 10d;
}
}
If you click on #mprivat's link and read the section on "The .class Syntax," what you get at the very beginning is:
If the type is available but there is no instance then it is possible
to obtain a Class by appending ".class" to the name of the type. This
is also the easiest way to obtain the Class for a primitive type.
So double.class works just fine.
I'd like to write a method that checks where the argument is null, and if it is, returns a new object of that type. it looks like:
public static <T> T checkNull(T obj) {
if (null == obj) return someHowCreateTheObjectWithTypeT();
else return obj;
}
After some struggling and digging, I still can't get a way to achieve this, is it atually possible in java?
I thought about reflection at first. But I just can't get a Class instance when the object is null, and you can't create a Class without the type T's name...
Update:
I thought about passing a Class as a parameter, but that's not the best solution, as the following answers shows :)
My currunt solution is to use a defaultValue parameter:
public static <T> T checkNull(T obj, T defaultValue) {
if (null == obj) return defaultValue;
return obj;
}
Which is faster and safer than a reflection solution, and is the same verbose;
But then I have to systematically specify a DEFAULT_VALUE for all types of interest, which is not an easy work.
This is not possible. For generics to work in this manner, it has to capture at compile-time the type that it will be called with. However, null has no type so you won't be able to figure out T to instantiate it.
Now, you may be able to work around this also passing in the Class instance, but you will need some rather robust error handling using Reflection to ensure that type T is a concrete class and has a public parameterless constructor that you can invoke.
Generic information is compile time only and not available at runtime. You'd have to pass the Class of the object in as a hint, and the class would have to have a public default constructor. e.g.
public static T checkNull(Object o, Class<T> c) {
try {
return (o == null) ? c.newInstance() : o;
} catch (Exception e) {
return null;
}
}
Cannot be done. You must add an additional parameter of Class<T>, and then use it to reflectively new. The type T does not survive the compilation process.
As others have pointed out, this can't be done. However, Guava provides an equivalent to the default value you method you posted:
String foo = Objects.firstNonNull(someString, "default");
This differs slightly from your method in that firstNonNull will throw a NullPointerException if both arguments are null.
Another option would be to create a method that makes use of Guava's Supplier<T> interface or something similar:
public static T firstNonNull(T first, Supplier<? extends T> defaultSupplier) {
return first != null ? first : Preconditions.checkNotNull(defaultSupplier.get());
}
You could then use a Supplier that creates and returns a new default instance when and only when the first argument is null.