As you will see below. I am writing a class named Property that can be bound to any Serializable type as evident from the class description.
Now the value in the property is auto bound to be of type T during compilation.
I want to implement a Class getType() method that should return the Class object of the value at runtime i.e.
Property<String> p = new Property<String>();
Class<String> cl = p.getType();
Here I expect cl to be String.class. Of course one way is:
return value == null ? null : value.getClass();
The issue is it won't reflect in the type returned and returns a raw type of Class object.
Ideally I want it to be of type Class<String>
public class Property<T extends Serializable> implements Serializable {
private T value = null ;
private String name = null ;
private boolean dirty = false ;
private Entity parent = null ;
public Class getType() {
// Here I want to determine the type of T that this object is bound to ?
return class;
}
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isDirty() {
return dirty;
}
public void setDirty(boolean dirty) {
this.dirty = dirty;
}
public Entity getParent() {
return parent;
}
public void setParent(Entity parent) {
this.parent = parent;
}
}
In short, you can't, because at runtime the type has been erased.
But, you can do this (abbreviated to just the relevant code):
public class Property<T extends Serializable> implements Serializable {
private T value = null;
private final Class<T> clazz;
// The constructor requires an instance of the Class<T>
public Property(Class<T> clazz) {
this.clazz = clazz;
}
// Return a typed Class object
public Class<T> getType() {
return clazz; // echo back a typed Class object pass to the constructor
}
The Class<T> object passed into the constructor is generally called a "type token".
It is not possible the way you are doing it due to type erasure. One consequence is that this the type that is used to instantiate the type parameter cannot be directly determined at runtime.
Here are a couple of alternatives:
1) Use getClass() to get the type of the value of the Property.
public Class getType() {
return value.getClass();
}
2) Explicitly pass the Class object for the actual type of T as constructor parameter. Note that the generic typing means that you can't accidentally pass the wrong Class object
private T value = null;
private Class<T> type;
public Property(Class<T> type) { this.type = type; }
public Class<T> getType() { this.type; }
There is another approach (which probably won't work here from a design perspective) where you reify the Property classes; e.g.
public class IntegerProperty extends Property<Integer> {
public Class getType() {
returns Integer.class;
}
}
There are clever variations of this where the subclass of the generic class in an anonymous class, and/or you access the type parameter via getClass().getTypeParameters(). But note that the getTypeParameters() approach only works if you've extended a generic class with specific types for the type parameters.
You can write a method
public Class<? extends T> getType() {
return value == null ? null : value.getClass();
}
This will return the runtime type of value, and at compile-time provide as much information about the returned class as possible: it will be T or any subclass of T.
If you want to always return Class<T>, then you have to provide the class as a runtime argument, the way #Bohemian describes it. The type arguments of a generic class aren't available at runtime due to type erasure.
Related
If I am writing a wrapper for a generic class, which I have tried to embed the type into at construction (as in this SO question):
class Foo<T> {
private T value;
private Class<T> type;
public Foo(Class<T> type, T value) {
this.value = value;
this.type = type;
}
public T getValue() {
return value;
}
public Class<T> getType() {
return type;
}
}
I have a list of instances of Foo, which I want to transform into a list of FooWrappers, along these lines:
List<Foo<?>> someListOfFoos = ...
List<FooWrapper<?>> fooWrappers = someListOfFoos
.stream()
.map(foo -> FooWrapper.from(foo))
.collect(Collectors.toList());
Is there any way to recover the type of each element in someListOfFoos when building each FooWrapper? Something along these lines:
class FooWrapper<T> {
private Foo<T> foo;
public static FooWrapper<?> from(Foo<?> toWrap) {
Class<E> type = toWrap.getType(); // i know this is wrong
return new FooWrapper<type>(toWrap); // this is very wrong
}
private FooWrapper(Foo<T> foo) {
this.foo = foo;
}
}
You just have to modify your FooWrapper#from slightly, by introducing a generic:
public static <E> FooWrapper<E> from(Foo<E> toWrap) {
return new FooWrapper<E>(toWrap);
}
I have an enum which has a property that is another class. I want to somewhere put a constraint that all instances of the enum have should have a value for that property that extend a certain upper bound, in this case an interface. Here is the basic working example without the bound:
public enum MyClassRegistry
{
MyClass(1,com.example.MyClass.class)
private int typeId;
private Class theClass;
}
What I want to do next is something like:
public enum MyClassRegistry
{
MyClass(1,com.example.MyClass.class)
private int typeId;
private Class<T extends SomeInterface> theClass;
}
To enforce that all values of this field extend a certain upper bound. Is this possible? If so, what is the syntax for this?
public enum MyClassRegistry
{
MyClass(1,com.example.MyClass);
private int typeId;
private Class<? extends SomeInterface> theClass;
MyClassRegistry(int typeId, Class<? extends SomeInterface> theClass) {
this.typeId = typeId;
this.theClass = theClass;
}
}
An enum type cannot declare any generic type parameters.
If you mean you want to have a field that has a type of some super type, an interface for example, simply declare the field as having that type.
public enum MyClassRegistry
{
First(1, new InterfaceFirstImpl()),
Second(2, new InterfaceSecondImpl()) ;
MyClassRegistry (int id, Interface value) {
this.typeId = id;
this.value = value;
}
private int typeId;
private Interface value;
}
I have a generic class as follows:
public MyClass<T>{
T id;
public T getId(){return id;}
public void setId(T id){this.id=id;}
}
I instantiate it as follows:
MyClass<String> myClass = new MyClass<String>();
When looking the getId() method through reflection (i == the index of the getId method):
myClass.getClass().getMethods()[i].getReturnType();
It will say that the return type is java.lang.Object.
I'm guessing I'm asking the impossible here, but, would it somehow be possible for the class to actually say java.lang.String in this case?
The reason I'm asking this is because I'm using App engine and it's Datastore. A simplified scenario: I got all my classes inheriting from MyClass and therefore they get a id with the type T, where T is either Long, String or Key. But the datastore thinks no matter what that the id field is an java.lang.Object, which is prohibited. Do I need to make classes like MyClassString, MyClassLong etc, or is there some way i can bypass this?
Thank you!
EDIT: After searching for another issue I had after "solving" this. I found this question actually mentioning my exact problem.
The type arguments for the parameterized type are lost at runtime through a process known as type erasure. At runtime there is no way to determine the method returns a String, since the actual type arguments used are not available.
Generic Faq
One way to work around this would be implement a generic interface, which would allow the objects to be used in a polymorphic manner:
Identifiable.java
public interface Identifiable<T> {
T getId();
void setId(T t);
}
Person.java
public class Person implements Identifiable<String> {
private String id;
#Override
public String getId() {
return id;
}
#Override
public void setId(String t) {
this.id = t;
}
public static void main(String[] args) {
Person person = new Person();
Method method = person.getClass().getMethods()[1]; //prints getId
System.out.println(method.getName());
System.out.println(method.getGenericReturnType()); //prints String
}
}
You could do this by storing a class variable within and returning this on request.
i.e.
public MyClass<T>{
Class<T> clazz;
T id;
public T getId(){return id;}
public void setId(T id){this.id=id;}
MyClass(Class<T> clazz) {
this.clazz=clazz
}
public Class<T> getIdClass() { return clazz; }
}
Now to find out what type your class is you can just call getIdClass() on it and use that returned type. Generics will enforce that the type is set correctly when an instance of MyClass is created.
A little modification can be added to Tim B's solution, if you do not want parametrized constructor.
public class MyClass<T>{
Class<T> clazz;
T id;
public T getId(){return id;}
public void setId(T id){this.id=id;}
public Class<?> getIdClass() {
if (id != null) {
return id.getClass();
} else {
return Object.class;
}
}
}
You can check it by
MyClass<String> myClass = new MyClass<String>();
myClass.setId("abc");
System.out.println(myClass.getIdClass());
For a project I'm working on, we have a lot of enums in use. The model object itself is composed from a lot of tiny classes; this model we then serialize to our DB as XML via JAXB. Now, we want to be able to serialize our enum values using the return of a particular method in the enum; that is given:
public enum Qualifier {
FOO("1E", "Foo type document"),
BAR("2", "Bar object");
private String code, description;
public Qualifier(String code, String description) {
this.code = code;
this.description = description;
}
public String getCode() {
return this.code;
}
public String getDescription() {
return this.description;
}
}
etc. etc. Currently, when serialized to XML, we get something like:
<qualifier>FOO</qualifier>
which is how JAXB handles it. However, we need the value to be the return of getCode(), and a whole lot of our enums do follow that convention (with a corresponding static method for lookup via code), so that the above XML fragment looks like:
<qualifier>1E</qualifier>
instead. We can annotate it with #XmlEnum and #XmlEnumValue, but that's too tedious -- some enums have up to 30 enumerated values, and hand-editing it is not good. We're also thinking of using a custom serializer instead, but I'd like to avoid going that route for now (but if that's the way to go, then I have no problem with it).
Any ideas how?
Try using the XmlAdapter mechanism for this. You create an XmlAdapter subclass for each enum type, and which knows how to marshal/unmarshal the enum to and from XML.
You then associate the adapter with the property, e.g.
public class QualifierAdapter extends XmlAdapter<String, Qualifier> {
public String marshal(Qualifier qualifier) {
return qualifier.getCode();
}
public Qualifier unmarshal(String val) {
return Qualifier.getFromCode(val); // I assume you have a way of doing this
}
}
and then in the model classes:
#XmlJavaTypeAdapter(QualifierAdapter.class)
private Qualifier qualifier;
You can also declare this at the package level, inside a file called package-info.java in the same package as your model classes, using the rather idiosyncratic package annotations:
#javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters({
#javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter(
type=Qualifier.class, value=QualifierAdapter.class
)
})
package com.xyz;
Found this question while looking for something else but I read your comment about something more generic. Heres what I have been using to convert upper case enum types to camel case. I am going to use your enum type but put my adapter on it. As you can see you dont need to reference every instance of Qualifier but just annotate the enum itself.
The CamelCaseEnumAdapter can take any enum however the enum class must be passed to it therefore you need to have a class extend it, I just use a private static class inside the enum itself.
Enum:
#XmlJavaTypeAdapter(Qualifier.Adapter.class)
public enum Qualifier {
FOO("1E", "Foo type document"),
BAR("2", "Bar object");
private String code, description;
public Qualifier(String code, String description) {
this.code = code;
this.description = description;
}
public String getCode() {
return this.code;
}
public String getDescription() {
return this.description;
}
private static class Adapter extends CamelCaseEnumAdapter<Qualifier> {
public Adapter() {
super(Qualifier.class, FOO);
}
}
}
Adapter
public abstract class CamelCaseEnumAdapter<E extends Enum> extends XmlAdapter<String, E>{
private Class<E> clazz;
private E defaultValue;
public CamelCaseEnumAdapter(Class<E> clazz) {
this(clazz, null);
}
public CamelCaseEnumAdapter(Class<E> clazz, E defaultValue) {
this.clazz = clazz;
this.defaultValue = defaultValue;
}
#Override
#SuppressWarnings("unchecked")
public E unmarshal(String v) throws Exception {
if(v == null || v.isEmpty())
return defaultValue;
return (E) Enum.valueOf(clazz, v.replaceAll("([a-z])([A-Z])", "$1_$2").toUpperCase());
}
#Override
public String marshal(E v) throws Exception {
if(v == defaultValue)
return null;
return toCamelCase(v.name());
}
private String toCamelCase(String s){
String[] parts = s.split("_");
String camelCaseString = "";
for (String part : parts){
if(camelCaseString.isEmpty())
camelCaseString = camelCaseString + part.toLowerCase();
else
camelCaseString = camelCaseString + toProperCase(part);
}
return camelCaseString;
}
private String toProperCase(String s) {
return s.substring(0, 1).toUpperCase() +
s.substring(1).toLowerCase();
}
}
I have several interfaces all with the same constants - ID and ROOT. I also have a method into which I pass an object that will be an implementation of one of these interfaces.
How can I dynamically retrieve the value of the constant depending on the class passed in - i.e. I want to do something like the following:
public void indexRootNode(Node node, Class rootNodeClass)
{
indexService.index(node, rootNodeClass.getConstant('ID'),
rootNodeClass.getConstant('ROOT'));
}
In PHP this is easy, but is this possible in Java? I've seen this problem solved using accessors on the constant, but I want to retrieve the constant directly. Annotations won't help me here either.
Thanks
This can be achieved using reflection (also see corresponding javadoc).
public void indexRootNode(Node node, Class rootNodeClass)
{
Field idField = rootNodeClass.getField("ID");
Object idValue = idField.get(null);
Field rootField = rootNodeClass.getField("ROOT");
Object rootValue = rootField.get(null);
indexService.index(node, idValue, rootValue);
}
Maybe you may additionaly have to cast the values to the corresponding type.
Please read chapter 19 use interfaces only to define types from Joshua Bloch's Effective Java (in fact, please read the entire book)
Constants do not belong in an interface!!! Constants should be tied to implementing classes, not interfaces.
Either use non-constant methods:
// the implementing classes can define these values
// and internally use constants if they wish to
public interface BaseInterface{
String id(); // or getId()
String root(); // or getRoot()
}
public interface MyInterface1 extends BaseInterface{
void myMethodA();
}
public interface MyInterface2 extends BaseInterface{
void myMethodB();
}
or use an enum to tie things together:
public enum Helper{
ITEM1(MyInterface1.class, "foo", "bar"),
ITEM2(MyInterface2.class, "foo2", "baz"),
;
public static String getId(final Class<? extends BaseInterface> clazz){
return fromInterfaceClass(clazz).getId();
}
public static String getRoot(final Class<? extends BaseInterface> clazz){
return fromInterfaceClass(clazz).getRoot();
}
private static Helper fromInterfaceClass(final Class<? extends BaseInterface> clazz){
Helper result = null;
for(final Helper candidate : values()){
if(candidate.clazz.isAssignableFrom(clazz)){
result = candidate;
}
}
return result;
}
private final Class<? extends BaseInterface> clazz;
private final String root;
private final String id;
private Helper(final Class<? extends BaseInterface> clazz,
final String root,
final String id){
this.clazz = clazz;
this.root = root;
this.id = id;
};
public String getId(){
return this.id;
}
public String getRoot(){
return this.root;
}
}
// use it like this
String root = Helper.fromInterfaceClass(MyInterface1.class).getRoot();