I'm sure this is a duplicate, but the keywords for my search are too common... I get a lot of hits, for things I'm not looking for. I'm coming from C#, and Java generics seem to be a bit behind the .NET implementation, so this is pretty frustrating for me.
I have an abstract class BaseRepository like so:
public abstract class BaseRepository<T, K> implements Repository<T, K> {
private Class<T> type;
private Class<K> keyType;
public BaseRepository(Class<T> clazz, Class<K> kClazz) {
type = clazz;
keyType = kClazz;
}
protected Class<T> getType() {
return type;
}
protected Class<K> getKeyType(){
return keyType;
}
}
Now I want to derive from my base class with an EmployeeRepository like so:
public class EmployeeRepository extends BaseRepository<Employee, UUID>{
}
With c#, I would not need to make such heroic efforts to instantiate the base class, but it seems java's implementation of generics requires you to pass the generic type(s) in the constructor.
So how do I create a parameterless constructor for my EmployeeRepository class that instantiates the base class with an entity type of Employee and a key type of UUID? I want to be able to write this:
EmployeeRepository foo = new EmployeeRepository();
... and have it instantiate the abstract class with Class<Employee> and Class<UUID>.
AFAIK, there is no way round this other than invoking the superclass constructor from the default subclass constructor thus:
public EmployeeRepository() {
super(Employee.class, UUID.class);
...
}
You could use reflection to determine the type of the generic arguments.
public abstract class BaseRepository<T, K> implements Repository<T, K> {
private Class<T> type;
private Class<K> keyType;
public BaseRepository() {
Type[] actualTypes = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments();
this.type = (Class<T>)actualTypes[0];
this.keyType = (Class<K>)actualTypes[1];
}
protected Class<T> getType() {
return type;
}
protected Class<K> getKeyType(){
return keyType;
}
}
However, the real question is: why do you want to have the types?
As an alternative, use the Builder pattern:
public class EmployeeRepository extends BaseRepository<Employee, UUID>{
public static EmployeeRepository newInstance() {
return new EmployeeRepository(Employee.class, UUID.class);
}
...
}
EmployeeRepository foo = EmployeeRepository.newInstance();
Related
I have an enum which is implements an interface. Enum:
enum MyEnum implements MyInterface {
ONE, TWO, THREE;
#Override
public MyEnum getFirst() {
return ONE;
}
}
Interface:
interface MyInterface<T extends Enum<T>> {
T getFirst();
}
Also I have a generic class with bounds:
class MyClass <T extends Enum<T> & MyInterface> {
private T firstElement;
private Class<T> enumType;
MyClass (Class<T> enumType) {
this.enumType = enumType;
}
}
So the main idea is to pass any enum (which is implements MyIterface) into constructor and then work with its constants. And this works for me. But also I want to store this first element into firstElement private field. I tried something like this:
firstElement = ((MyInterface)enumType).getFirst();
But still no success. I can't cast java.lang.Class<T> to MyInterface. Any ideas how to achieve this? Thanks in advance!
UPDATE: My problem is not about how to take the first enum constant. I know about .ordinal() and .values()[0];. I want to create reusable generic class and use it with any enums, marked by some interface.
Ok, let it not be getFirst() method. Let it be getDefault()
I think you could use Supplier<T> as an argument for your constructor instead of Class<T>:
class MyClass<T extends Enum<T> & MyInterface<T>> {
private T firstElement;
private Class<T> enumType;
#SuppressWarnings("unchecked")
MyClass (Supplier<T> enumSupplier) {
T actualEnum = enumSupplier.get();
this.enumType = (Class<T>) actualEnum.getClass();
this.firstElement = actualEnum.getFirst();
}
}
That cast throws a warning, but it can be safely suppressed, since Supplier<T> will return an instance of T, and T is both Enum<T> and MyInterface<T>, so the class of actualEnum will always be Class<T>.
I would like to suggest you a few corrections: as MyInterface is generic, you should always use it along with a generic type (this is why I've declared MyClass as MyClass<T extends Enum<T> & MyInterface<T>>). The same goes for MyEnum: it should be defined as MyEnum implements MyInterface<MyEnum>.
With the above changes in place, you can now create an instance of MyClass as follows:
MyClass<MyEnum> myClass = new MyClass<>(() -> MyEnum.THREE); // Or ONE or TWO
System.out.println(myClass.firstElement); // ONE
From your context I think you need getFirst() because you want to get the first value of a enum. However, you don't need getFirst() at all. All you need is this:
class <T extends Enum<T> & MyInterface> MyClass {
private T firstElement;
private Class<T> enumType;
MyClass (Class<T> enumType) {
this.enumType = enumType;
firstElement = enumType.getEnumConstants()[0];
}
}
You can just remove all those getFirst() in all of your classes.
You can call getFirst only on an enum object which implements MyInterface but not on its class. You can write:
firstElement = enumType.getEnumConstants()[0].getFirst();
interface MyInterface {
MyInterface getFirst();
MyInterface[] getConstants();
}
enum MyEnum implements MyInterface {
ONE, TWO, THREE;
#Override
public MyInterface getFirst() {
return ONE;
}
#Override
public MyInterface[] getConstants() {
return new MyInterface[] {ONE, TWO, THREE};
}
}
class MyClass {
private MyInterface firstElement;
MyClass (MyInterface enumType) {
this.firstElement = enumType.getFirst();
}
}
So, using the above design I think you can "pass any enum (which is implements MyInterface) into constructor and then work with its constants."
here's my code:
AbstractClass
public abstract class AbstractClass<T>{
public abstract Class<?> getPersistentClass();
public void invokeNothing(){
Class<T> c = getPersistentClass();
// do something....
// some code...
}
}
CommonClass
public class CommonClass<T> extends AbstractClass<T>{
public Class<?> getPersistentClass(){
// how to get the persistent class of generic T
// T.class
return // T.class
}
}
Service
public class CommonService{
#Autowired
private CommonAbstractClass<Person> commonClass;
public void invoke(){
commonClass.invokeNothing();
}
}
how to get the persistent class parameter of a class generic? in my class CommonClass in method getPersistentClass();
please help me thanks...
Actually there is no way (at least no easy way I am aware of except reflection in some cases) to get the runtime type of the generic type parameter due to type erasure. You can use the following safe work-around:
public class CommonClass<T>{
private final Class<T> type;
public CommonClass(Class<T> type) {
this.type = type;
}
public Class<T> getMyType() {
return this.type;
}
}
But you may need to instantiate it like:
CommonClass<Person> cp = new CommonClass<Person>(Person.class);
If you are using Spring you can find this answer useful.
So far, the best way I could handle returning the subclass type in the superclass is passing the subclass type as type parameter.
It doesn't look pretty though, so I need to know if there is a better approach to accomplish this.
This is what I have:
public abstract class Model<R extends Model<R, ID>, ID extends Serializable> {
public R find(ID id) {
return find(getClass(), id);
}
...
}
public final class SampleRecord extends Model<SampleRecord, Long> {
#Id
private Long id;
}
I have a class:
public class MultipleSorting<T extends Enum<?>> {
private T criteriaType;
public Class<T> getCriteriaClass() {
Field field = ReflectionUtils.getField(getClass(),"criteriaType");
ReflectionUtils.makeAccessible(field);
return (Class<T>)field.getType();
}
}
This class is get instantiated as:
public abstract class MultiSortPageableController<T extends MultiSortPageableController<?,?>, U extends Enum<?>> {
private MultipleSorting<U> multipleSorting;
public MultiSortPageableController() {
super();
multipleSorting = new MultipleSorting<U>();
}
}
The actual value of U is passed from the child class of MultiSortPageableController which is:
public abstract class AbstractArticleSearchController<T extends AbstractArticleSearchController<T>> extends MultiSortPageableController<T,ArticleSortField> {
}
The ArticleSortField is an Enum.
I was expecting the method getCriteriaClass of MultipleSorting would return ArticleSortField from a method of MultiSortPageableController. But it is returning java.lang.Enum.
I am unable to figure it out why it is not returning the actual enum and how can I make it so. Any pointer would be very helpful to me. I need to get ArticleSortField.
Purpose:
I two requirement:
To get the actual class of enum type (say ArticleSortField.class)
To list enum value. If I have the enum class, then I could invoke class..getEnumConstants().
Java compiler removes information about generics, therefore when you use reflection you get no information about the declared type, other than Enum. This process is called type erasure.
How about passing the type down, via the constructor, like this:
public class MultipleSorting<T extends Enum<?>> {
private Class<T> criteriaType;
MultipleSorting(Class<T> criteriaType) {
this.criteriaType = criteriaType;
}
public Class<T> getCriteriaClass() {
return criteriaType;
}
}
public abstract class MultiSortPageableController<T extends MultiSortPageableController<?, ?>, U extends Enum<?>> {
private MultipleSorting<U> multipleSorting;
public MultiSortPageableController(Class<U> criteriaType) {
super();
multipleSorting = new MultipleSorting<U>(criteriaType);
}
}
public abstract class AbstractArticleSearchController<T extends AbstractArticleSearchController<T>> extends MultiSortPageableController<T, ArticleSortField> {
public AbstractArticleSearchController() {
super(ArticleSortField.class);
}
}
Can someone explain to me why the following code does not work?
public class TestGeneric {
EntityManager entityManager = new EntityManager();
public <T extends Textable & Entity> void doAction(T obj) {
entityManager.getAliasForEntityClass(obj.getClass());
}
}
class EntityManager {
public String getAliasForEntityClass(Class<? extends Entity> clazz) {
return clazz.getCanonicalName();
}
}
interface Entity {
Long getId();
}
interface Textable {
String getText();
}
I'm getting the following error:
The method getAliasForEntityClass(Class<? extends Entity>) in the type EntityManager is not applicable for the arguments
(Class<capture#1-of ? extends Textable>)
If I wrote in this way, I did not have any error:
public class TestGeneric {
EntityManager entityManager = new EntityManager();
public <T extends Entity & Textable> void doAction(T obj) {
entityManager.getAliasForEntityClass(obj.getClass());
}
}
class EntityManager {
public String getAliasForEntityClass(Class<? extends Entity> clazz) {
return clazz.getCanonicalName();
}
}
interface Entity {
Long getId();
}
interface Textable {
String getText();
}
Template <T extends Entity & Textable> and <T extends Textable & Entity> means: T must implements Entity and Textable interfaces. Why position of interface so important in this example?
The reason is that the erasure of T is the leftmost type in the bound. From the getClass() documentation:
The actual result type is Class<? extends |X|> where |X| is the
erasure of the static type of the expression on which getClass is
called.
The JLS specifies that "the erasure of a type variable is the erasure of its leftmost bound" (see here). So the type of obj.getClass() is Class<? extends Textable> in the first case and Class<? extends Entity> in the other.