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());
Related
I have a super class that has a protected final field, so it has to create a constructor with parameter, like this:
public SuperClass<ID> implements Serializable {
protected final ID id;
public SuperClass(ID id) {
this.id = id;
}
}
Then subclass also needs to create a constructor with parameter to initialize the inherited field.
public SubClass extends SuperClass<UUID> {
public SubClass(UUID id) {
super(id);
}
}
Now I have a problem is I need a constructor without parameter for other use(e.g Jackson's deserialize). So is there any solution to solute this problem?
Thanks in advance.
Sure. You have to call the superclass's constructor with a value, since that's the only option you have. But there's no reason that value has to come from a parameter to your constructor:
public SubClass extends SuperClass<UUID> {
public SubClass() {
super(UUID.fromString("whatever"); // Exactly what you pass is up to you
}
public SubClass(UUID id) {
super(id);
}
}
PS: I'm not sure what that 'ID' type is that the superclass's constructor takes. Did you mean UUID?
I like to make a generic enum that accepts anything.
For this example I use TaskStatus, but in the future, I like to use Generic Enum for example; StudentStatus, this student status can take an id and description itself and it will convert automatically. Moreover, iterate every object and finally automatically return. Is there any chance I can make it?
#Getter
#AllArgsConstructor(access = AccessLevel.PRIVATE)
public enum TaskStatusEnum{
READY(1, "Ready"),
ON_GOING (2,"On going");
private final long id;
private final String description;
public static TaskStatusEnum get (long id)
{
for (TaskStatusEnum status : TaskStatusEnum.values()) {
if (status.id == id) {
return id;
}
}
return null;
}
I'm not sure what exactly you want. You can use interface on enum, then you can use interface as status and dont care what exactly status class is.
public interface Status<E extends Enum<E> & Status<E>> {
public long getId();
public String getDescription();
}
student status:
public enum StudentStatus implements Status<StudentStatus>{
NEW(0, "new");
;
private long id;
private String description;
private StudentStatus(long id, String description) {
this.id=id;
this.description = description;
}
#Override
public long getId() {
return id;
}
#Override
public String getDescription() {
return description;
}
}
task status:
public enum TaskStatus implements Status<TaskStatus>{
OPEN(0, "open");
;
private long id;
private String description;
private TaskStatus(long id, String description) {
this.id=id;
this.description = description;
}
#Override
public long getId() {
return id;
}
#Override
public String getDescription() {
return description;
}
}
generic method to find out status by id
public abstract class StatusUtil {
public static <E extends Enum<E> & Status<E>> E get(Class<E> statusClass, long id) {
return Arrays.asList((E[]) statusClass.getEnumConstants())
.stream()
.filter(item -> item.getId() == id)
.findAny()
.orElse(null);
}
}
example how use:
public class Test {
public static void main(String... args) {
StudentStatus studentStatus = StatusUtil.get(StudentStatus.class, 0);
TaskStatus taskStatus = StatusUtil.get(TaskStatus.class, 0);
List<Status> statusList = Arrays.asList(studentStatus, taskStatus);
statusList.forEach(status -> System.out.println(status.getClass().getName()+"\t"+status.getId()+"\t"+status.getDescription()));
}
}
if you use JAVA below 8:
public interface Status<E extends Enum<E>> {
public long getId();
public String getDescription();
}
statusUtil:
public abstract class StatusUtil {
public static <E extends Enum<E>> E get(Class<E> statusClass, long id) {
for(E item: (E[]) statusClass.getEnumConstants()) {
if(item.getId() == id) {
return item;
}
}
return null;
}
}
test:
public static void main(String... args) {
StudentStatus studentStatus = StatusUtil.get(StudentStatus.class, 0);
TaskStatus taskStatus = StatusUtil.get(TaskStatus.class, 0);
List<Status> statusList = Arrays.asList(studentStatus, taskStatus);
for(Status status: statusList) {
System.out.println(status.getClass().getName()+"\t"+status.getId()+"\t"+status.getDescription());
}
}
This you can use in cases, when enums has this same methods and you need common interface
Your enum is effectively final (no subclass allowed)
Apparently you are asking if TaskStatus enum can be subclassed. For example making a StudentStatus that inherits from TaskStatus.
➥ No, enums in Java cannot be subclassed.
Your enum definition actually is a subclass of Enum. That happens in the background, magically handled by the compiler. The inheritance stops there. Your enum definition is effectively final, not allowing further subclasses.
An enum definition can implement an interface. Instances from multiple enum definitions can be treated as all being objects of the same interface. See Answer by Victor1125.
An enum in Java is a convenient way to automatically instantiate one or more name objects, to represent a limited set of values known at compile time. Those instances all pop into existence when their definition class is loaded by the Java classloader. Those objects remain in memory.
You cannot add more instances dynamically at runtime. The entire domain of the enum’s objects is defined at compile time. (Exception: Some crazy twisted reflection/introspection code may be able to create more instances, but I would not go there.)
If you want inheritance, or dynamically created instances, do not use enums. Use regular classes and subclasses, collected into sets or lists. The sets or lists can be marked (< … >) with generics to allow the superclass of their contained elements. For example Set< Animal > can contain objects of the subclasses Dog, Cat, and Bird.
By the way, you can now define an enum in 3 places: its own class, nested within another class, and now in Java 16 (previewed in Java 15), locally inside a method.
Tip: No need to put "Enum" within the name of your enum. Endeavor to invent names for your enum class and enum objects that read naturally. The fact that they happen to be an enum should fade into the background. For example: See Month (Month.JANUARY) and DayOfWeek (DayOfWeek.MONDAY).
How to handle null point on StatusUtil.class
StatusUtil:
public abstract class StatusUtil {
public static <E extends Enum<E>> E get(Class<E> statusClass, long id) {
for(E item: (E[]) statusClass.getEnumConstants()) {
if(item.getId() == id) {
return item;
}
}
return null;
}
i have made a class like this
public class Item<IdType> {
public IdType id;
public String name;
}
public class Dealer<IdType> {
public IdType id;
public String name;
}
and a function in other class like this :
public <T> boolean deleteById(Class<Class<T>> modelClass, T id) {
daooperation();
return true;
}
what i want to do is when i call the function deleteById with parameter 1 is Item<Long> then parameter 2(id) should use Long datatype too
other example is deleteById with parameter 1 is Dealer<String> then parameter 2(id) should use String datatype too. how to parse parameter 1(modelClass) to function deleteById or shoud i change the parameter 1(modelClass) in deleteById?
please someone help me, show me how can i do that.
I think your methods should look more like this.
public static <I extends Item<T>, T> boolean deleteById(I item, T id) {
doSomething();
return true;
}
public static <D extends Dealer<T>, T> boolean deleteById(D dealer, T id) {
doSomething();
return true;
}
Object.Class method is your solution I guess
Due to the way type erasure and Java generics work, the best you can do is:
public class Test {
public static <T extends WithId<B>, B> boolean foo(T obj, B id) {
obj.id = id;
return true;
}
public static void main(String[] args) {
Bla<String> bar = new Bla<String>();
foo(bar, "123"); // Works
foo(bar, 123 ); // Fails
}
}
abstract class WithId<T> {
T id;
}
class Bla<T> extends WithId<T> {
// ...
}
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.
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();