Generics Entity and EntityDTO similar methods - java

Is there any way to unite getEntityId and getEntityDTOId?
public class Entity {
private Integer id;
public Integer getId() {return id;}
}
public class EntityDTO {
private Integer id;
public Integer getId() {return id;}
}
public class EntityProcessing {
public Integer getEntityId(Entity entity) {
return entity.getId();
}
public Integer getEntityDTOId(EntityDTO entityDTO) {
return entityDTO.getId();
}
}
I've read about Generics, but can't understand how to implement them in such a case.

You can for example create some interface:
public interface WithId {
Integer getId();
}
and implement it (you need to implement this interface in all the classes you want to use in the EntityProcessing.getId method):
public class Entity implements WithId { // add implements ...
private Integer id;
#Override // add to mark that it's method from the interface
public Integer getId() {return id;}
}
And now you can create one method to get id from all the classes implementing WithId interface:
public Integer getId(WithId withId) {
return withId.getId();
}
The other option is to use abstract class containing the id field. But it's against Liskov Substitution Principle (L from SOLID object oriented programming principles).
And there is a limitation, that you can extend only one class in java, but you can implement multiple interfaces. So in my opinion better use interface like above, but for completeness I added this solution as well.
public abstract class WithId {
private Integer id;
public Integer getId() {
return id;
}
}
and extend the abstract class:
public class Entity extend WithId { // in this case add extend ...
// you don't need to add anything here,
// because field and the method are already present in the base class
}
And usage is the same as in the first solution above.
This solution at the first glance seems to be better because you can write the method only once in the abstract class, but you have to remember the limitations (you can extend only one class in java), because if you want in the future add another common field like e.g. createdDate - you can implement second interface e.g. WithCreatedDate, but you cannot extend second class

The example you provided, doesn't actually need to use generics, but it looks like you're learning about generics:
public class Test {
public static void main(String[] args) {
Entity entity = new Entity();
EntityDTO entityDTO = new EntityDTO();
EntityProcessing<Base> a = new EntityProcessing<>();
System.out.println(a.getEntityId(entity));
System.out.println(a.getEntityId(entityDTO));
System.out.println(EntityProcessing.getId(entity));
System.out.println(EntityProcessing.getId(entityDTO));
}
}
interface Base {
public Integer getId();
}
class Entity implements Base {
private Integer id = 1;
public Integer getId() {return id;}
}
class EntityDTO implements Base {
private Integer id = 2;
public Integer getId() {return id;}
}
// T must be a subtype of Base, otherwise, after generic erasure, the T type does not have a getId method
class EntityProcessing<T extends Base> {
public Integer getEntityId(T entity) {
return entity.getId();
}
// Generics Method
// T must be a subtype of Base, otherwise, after generic erasure, the T type does not have a getId method
// Note that there is no relationship between the <T> in the generic method and the <T> in the life of the generic class.You can completely replace the T here with an R, or any other char
// public static <F extends Base> Integer getId(F entity)
// public static <ABC extends Base> Integer getId(ABC entity)
// .....
public static <T extends Base> Integer getId(T entity) {
return entity.getId();
}
}

Related

How can I use inheritance for parameters type in a method call?

I am developing a Java web application for a school project and I am following the MVC architecture pattern as best as I can; to accomplish that, I created a set of JavaBean classes, and to serialize and deserialize instances of these I am using Gson. The problem I'm having shows that I haven't fully understood how inheritance and generics work in Java, so I hope to shed light on those arguments with this question.
I have two abstract classes Item and ItemVariant, which are extended by two bean classes each, respectively CatalogItem, ArchivedItem and CatalogItemVariant, ArchivedItemVariant.
An istance of Item can refer to a collection of ItemVariant, and vice versa, an istance of ItemVariant can refer to its parent item (I know this can cause loops in the serialization process but this isn't the problem I am experiencing). So ideally, an instance of CatalogItem should always refer to a collection CatalogItemVariant and an instance of CatalogItemVariant should always refer to one of CatalogItem, and the same applies for ArchivedItem and ArchivedItemVariant. However, I am not interested into forcing this relationship; for example, letting an instance of CatalogItemVariant refer to an instance of ArchivedItem is allowed.
Currently the code for these two abstract classes looks like this:
public abstract class Item implements Serializable {
...
protected Collection<ItemVariant> variants;
...
public <T extends ItemVariant> Collection<T> getVariants() {
return (Collection<T>) variants;
}
...
public <T extends ItemVariant> void setVariants(Collection<T> variants) {
this.variants = (Collection<ItemVariant>) variants;
}
}
public abstract class ItemVariant implements Serializable {
...
protected Item parentItem;
...
public <T extends Item> T getParentItem() {
return (T) parentItem;
}
...
public <T extends Item> void setParentItem(T parentItem) {
this.parentItem = parentItem;
}
...
}
This is producing unchecked cast warnings and I am aware that it probably isn't the most elegant solution; however, this isn't the major issue that I'm experiencing.
The bean classes that extend these two simply add a couple properties each along with their getters and setters, and instances of those concrete classes are the ones actually used throughout the application. Now comes the real problem: consider, as an example, the following JSON string that must be deserialized into an instance of CatalogItemVariant.
{"parentItem":{"name":"Sample name","category":"Sample category","color":"Sample color"},"size":"Sample size"}
Ideally, parentItem should be deserialized into an istance of CatalogItem, but given the way those classes are currently designed, Gson tries to create an instance of Item, which is abstract and thus causes the following exception:
java.lang.RuntimeException: Failed to invoke public model.transfer.catalog.Item() with no args
To work around this, I thought of making the two methods setVariants in Item and setParentItem in ItemVariant abstract, thus forcing their subclasses two override them. Something like this:
public abstract class ItemVariant implements Serializable {
...
protected Item parentItem;
...
public abstract <T extends Item> void setParentItem(T parentItem);
...
}
public class CatalogItemVariant extends ItemVariant {
...
#Override
public void setParentItem(CatalogItem parentItem) {
this.parentItem = parentItem;
}
...
}
But this isnt working because the type CatalogItem doesn't match T, making the #Override annotation invalid.
A workaround to this would be sending to the servlet that deserializes the object two separate JSON strings, one for the item variant and one for its parent item, deserialize both of them into two different objects using the correct classes (CatalogItem for the first one and CatalogItemVariant for the second), and then manually set the attribute parentItem of the new CatalogItemVariant instance using setParentItem(). Of course, when applying this solution, the JSON string for the item variant must miss its parentItem field. Is there a better solution to this? If so, how should I redesign the classes and methods that are affected by this problem?
EDIT: since I've been asked to provide the actual code, here's a simplified version of the classes I'm using:
public abstract class Item implements Serializable {
private static final long serialVersionUID = -6170402744115745097L;
protected String name;
protected String category;
protected String color;
protected Collection<ItemVariant> variants;
public String getName() {
return this.name;
}
public String getCategory() {
return this.category;
}
public String getColor() {
return this.color;
}
public <T extends ItemVariant> Collection<T> getVariants() {
return (Collection<T>) variants;
}
public void setName(String name) {
this.name = name;
}
public void setCategory(String category) {
this.category = category;
}
public void setColor(String color) {
this.color = color;
}
public <T extends ItemVariant> void setVariants(Collection<T> variants) {
this.variants = (Collection<ItemVariant>) variants;
}
}
public abstract class ItemVariant implements Serializable {
private static final long serialVersionUID = 4245549003952140725L;
protected Item parentItem;
protected String size;
public <T extends Item> T getParentItem() {
return (T) parentItem;
}
public String getSize() {
return size;
}
public <T extends Item> void setParentItem(T parentItem) {
this.parentItem = parentItem;
}
public void setSize(String size) {
this.size = size;
}
}
public class CatalogItem extends Item implements Serializable {
private static final long serialVersionUID = 993286101083002293L;
protected String description;
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
public class CatalogItemVariant extends ItemVariant implements Serializable {
private static final long serialVersionUID = -2266390484210707778L;
protected Integer availability;
public Integer getAvailability() {
return availability;
}
public void setAvailability(Integer availability) {
this.availability = availability;
}
}
The error I'm experienced can be simulated by running the following snippet of code, and it's thrown in the last line:
Gson gson = new GsonBuilder().create();
CatalogItem catalogItem;
CatalogItemVariant catalogItemVariant;
CatalogItemVariant deserializedCatalogItemVariant;
catalogItem = new CatalogItem();
catalogItem.setName("Sample name");
catalogItem.setCategory("Sample category");
catalogItem.setColor("Sample color");
catalogItemVariant = new CatalogItemVariant();
catalogItemVariant.setSize("Sample size");
catalogItemVariant.setParentItem(catalogItem);
String serializedCatalogItemVariant = gson.toJson(catalogItemVariant); // Builds a JSON string of the object to serialize
System.out.println(serializedCatalogItemVariant); // Prints the JSON string of the serialized object which is fed for deserialization in the next instruction
deserializedCatalogItemVariant = gson.fromJson(serializedCatalogItemVariant, CatalogItemVariant.class);
For clarification, I fully understand that the error is caused because of the way these classes are designed and I don't expect the program to behave differently; I just want to understand if there's a way I can use generics and inheritance to redesign those classes, and if so, what that way is.
For anyone who runs into this question, have a look at this very simple solution!

Does a Java enum itself extend an interface I can make use of?

I have several enums which implement an interface I've defined. Now I'd like to provide some boilerplate operations on these enums based on their common interface as well as their common enum ancestry. Is this possible?
In other words, I have:
public enum Car implements Vehicle {
FORD, HONDA;
}
public interface Vehicle {
String getLicensePlate();
}
And I'd now like to write something like this, perhaps in a default interface method or some other common place:
public static showLicensePlates(Vehicle.class vEnum) {
for(Vehicle v : vEnum.values()) {
System.out.println(v.getLicensePlate());
}
}
Notice how I'm relying on enum's "values()" method, so the interface must be an enum for this to work. How can I specify that this interface must be an enum? Or if that's not possible, how an I write boilerplate methods to operate on enums in general?
What you want is for the showLicensePlates() method to only take an argument that is both a vehicle and enum. This is done with generics:
public <T extends Enum & Vehicle> showLicensePlates(T vEnum) {
//do stuff
}
Can call
Vehicle.class.getEnumConstants()
If it does not return null,then its an enum.
Java doc says:
Returns the elements of this enum class or null if this Class object does not represent an enum type.
Since you have the interface and the Enumerator implemets such... then you can adapt the enum to return some Ids and...
interface Vehicle {
String getLicensePlate();
}
enum Car implements Vehicle {
FORD("F-007"), HONDA("H-860");
private final String id;
private Car(String id) {
this.id = id;
}
#Override
public String getLicensePlate() {
return this.id;
}
}
...and play with the Constraints in the method ShowLicenseMEthod.
public class Abc {
public static void main(String[] args) {
Abc c = new Abc();
c.showLicensePlates(Car.class);
}
public <E extends Enum<E> & Vehicle> void showLicensePlates(Class<E> vEnum) {
for (E v : vEnum.getEnumConstants()) {
System.out.println(v.getLicensePlate());
}
}
}
Then you can pass ALL the enum classes you have and the method will print the LicensePlates of all the Enum Constants...

How to use the subclass type as return on a method on a super class?

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;
}

Is it possible to write a generic enum converter for JPA?

I wanted to write a Converter for JPA that stores any enum as UPPERCASE. Some enums we encounter do not follow yet the convention to use only Uppercase letters so until they are refactored I still store the future value.
What I got so far:
package student;
public enum StudentState {
Started,
Mentoring,
Repeating,
STUPID,
GENIUS;
}
I want "Started" to be stored as "STARTED" and so on.
package student;
import jpa.EnumUppercaseConverter;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
#Entity
#Table(name = "STUDENTS")
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long mId;
#Column(name = "LAST_NAME", length = 35)
private String mLastName;
#Column(name = "FIRST_NAME", nullable = false, length = 35)
private String mFirstName;
#Column(name = "BIRTH_DATE", nullable = false)
#Temporal(TemporalType.DATE)
private Date mBirthDate;
#Column(name = "STUDENT_STATE")
#Enumerated(EnumType.STRING)
#Convert(converter = EnumUppercaseConverter.class)
private StudentState studentState;
}
the converter currently looks like this:
package jpa;
import javax.persistence.AttributeConverter;
import java.util.EnumSet;
public class EnumUppercaseConverter<E extends Enum<E>> implements AttributeConverter<E, String> {
private Class<E> enumClass;
#Override
public String convertToDatabaseColumn(E e) {
return e.name().toUpperCase();
}
#Override
public E convertToEntityAttribute(String s) {
// which enum is it?
for (E en : EnumSet.allOf(enumClass)) {
if (en.name().equalsIgnoreCase(s)) {
return en;
}
}
return null;
}
}
what will not work is that I do not know what enumClass will be at runtime. And I could not figure out a way to pass this information to the converter in the #Converter annotation.
So is there a way to add parameters to the converter or cheat a bit? Or is there another way?
I'm using EclipseLink 2.4.2
Thanks!
Based on #scottb solution I made this, tested against hibernate 4.3: (no hibernate classes, should run on JPA just fine)
Interface enum must implement:
public interface PersistableEnum<T> {
public T getValue();
}
Base abstract converter:
#Converter
public abstract class AbstractEnumConverter<T extends Enum<T> & PersistableEnum<E>, E> implements AttributeConverter<T, E> {
private final Class<T> clazz;
public AbstractEnumConverter(Class<T> clazz) {
this.clazz = clazz;
}
#Override
public E convertToDatabaseColumn(T attribute) {
return attribute != null ? attribute.getValue() : null;
}
#Override
public T convertToEntityAttribute(E dbData) {
T[] enums = clazz.getEnumConstants();
for (T e : enums) {
if (e.getValue().equals(dbData)) {
return e;
}
}
throw new UnsupportedOperationException();
}
}
You must create a converter class for each enum, I find it easier to create static class inside the enum: (jpa/hibernate could just provide the interface for the enum, oh well...)
public enum IndOrientation implements PersistableEnum<String> {
LANDSCAPE("L"), PORTRAIT("P");
private final String value;
#Override
public String getValue() {
return value;
}
private IndOrientation(String value) {
this.value= value;
}
public static class Converter extends AbstractEnumConverter<IndOrientation, String> {
public Converter() {
super(IndOrientation.class);
}
}
}
And mapping example with annotation:
...
#Convert(converter = IndOrientation.Converter.class)
private IndOrientation indOrientation;
...
With some changes you can create a IntegerEnum interface and generify for that.
What you need to do is write a generic base class and then extend that for each enum type you want to persist. Then use the extended type in the #Converter annotation:
public abstract class GenericEnumUppercaseConverter<E extends Enum<E>> implements AttributeConverter<E, String> {
...
}
public FooConverter
extends GenericEnumUppercaseConverter<Foo>
implements AttributeConverter<Foo, String> // See Bug HHH-8854
{
public FooConverter() {
super(Foo.class);
}
}
where Foo is the enum you want to handle.
The alternative would be to define a custom annotation, patch the JPA provider to recognize this annotation. That way, you could examine the field type as you build the mapping information and feed the necessary enum type into a purely generic converter.
Related:
https://hibernate.atlassian.net/browse/HHH-8854
This answer has been modified to take advantage of default interface methods in Java 8.
The number of components of the facility (enumerated below) remains at four, but the amount of required boilerplate is much less. The erstwhile AbstractEnumConverter class has been replaced by an interface named JpaEnumConverter which now extends the JPA AttributeConverter interface. Moreover, each placeholder JPA #Converter class now only requires the implementation of a single abstract method that returns the Class<E> object for the enum (for even less boilerplate).
This solution is similar to others and also makes use of the JPA Converter facility introduced in JPA 2.1. As generic types in Java 8 are not reified, there does not appear to be an easy way to avoid writing a separate placeholder class for each Java enum that you want to be able to convert to/from a database format.
You can however reduce the process of writing an enum converter class to pure boilerplate. The components of this solution are:
Encodable interface; the contract for an enum class that grants access to a String token for each enum constant. This is written only once and is implemented by all enum classes that are to be persisted via JPA. This interface also contains a static factory method for getting back the enum constant for its matching token.
JpaEnumConverter interface; provides the common code for translating tokens to/from enum constants. This is also only written once and is implemented by all the placeholder #Converter classes in the project.
Each Java enum class in the project implements the Encodable interface.
Each JPA placeholder #Converter class implements the JpaEnumConverter interface.
The Encodable interface is simple and contains a static factory method, forToken(), for obtaining enum constants:
public interface Encodable{
String token();
public static <E extends Enum<E> & Encodable> E forToken(Class<E> cls, String tok) {
final String t = tok.trim();
return Stream.of(cls.getEnumConstants())
.filter(e -> e.token().equalsIgnoreCase(t))
.findAny()
.orElseThrow(() -> new IllegalArgumentException("Unknown token '" +
tok + "' for enum " + cls.getName()));
}
}
The JpaEnumConverter interface is a generic interface that is also simple. It extends the JPA 2.1 AttributeConverter interface and implements its methods for translating back and forth between entity and database. These are then inherited by each of the JPA #Converter classes. The only abstract method that each placeholder class must implement, is the one that returns the Class<E> object for the enum.
public interface JpaEnumConverter<E extends Enum<E> & Encodable>
extends AttributeConverter<E, String> {
public abstract Class<E> getEnumClass();
#Override
public default String convertToDatabaseColumn(E attribute) {
return (attribute == null)
? null
: attribute.token();
}
#Override
public default E convertToEntityAttribute(String dbData) {
return (dbData == null)
? null
: Encodeable.forToken(getEnumClass(), dbData);
}
}
An example of a concrete enum class that could now be persisted to a database with the JPA 2.1 Converter facility is shown below (note that it implements Encodable, and that the token for each enum constant is defined as a private field):
public enum GenderCode implements Encodable{
MALE ("M"),
FEMALE ("F"),
OTHER ("O");
final String e_token;
GenderCode(String v) {
this.e_token = v;
}
#Override
public String token() { // the only abstract method of Encodable
return this.e_token;
}
}
The boilerplate for every placeholder JPA 2.1 #Converter class would now look like the code below. Note that every such converter will need to implement JpaEnumConverter and provide the implementation for getEnumClass() ... and that's all! The implementations for the JPA AttributeConverter interface methods are inherited.
#Converter
public class GenderCodeConverter
implements JpaEnumConverter<GenderCode> {
#Override
public Class<GenderCode> getEnumClass() { // sole abstract method
return GenderCode.class;
}
}
These placeholder #Converter classes can be readily nested as static member classes of their associated enum classes.
The above solutions are really fine. My small additions here.
I also added the following to enforce when implementing the interface writing a converter class. When you forget jpa starts using default mechanisms which are really fuzzy solutions (especially when mapping to some number value, which I always do).
The interface class looks like this:
public interface PersistedEnum<E extends Enum<E> & PersistedEnum<E>> {
int getCode();
Class<? extends PersistedEnumConverter<E>> getConverterClass();
}
With the PersistedEnumConverter similar to previous posts. However when the implementing this interface you have to deal with the getConverterClass implementation, which is, besides being an enforcement to provide the specific converter class, completely useless.
Here is an example implementation:
public enum Status implements PersistedEnum<Status> {
...
#javax.persistence.Converter(autoApply = true)
static class Converter extends PersistedEnumConverter<Status> {
public Converter() {
super(Status.class);
}
}
#Override
public Class<? extends PersistedEnumConverter<Status>> getConverterClass() {
return Converter.class;
}
...
}
And what I do in the database is always make a companion table per enum with a row per enum value
create table e_status
(
id int
constraint pk_status primary key,
label varchar(100)
);
insert into e_status
values (0, 'Status1');
insert into e_status
values (1, 'Status2');
insert into e_status
values (5, 'Status3');
and put a fk constraint from wherever the enum type is used. Like this the usage of correct enum values is always guaranteed. I especially put values 0, 1 and 5 here to show how flexible it is, and still solid.
create table using_table
(
...
status int not null
constraint using_table_status_fk references e_status,
...
);
I found a way to do this without using java.lang.Class, default methods or reflection. I did this by using a Function that is passed to the Convertor in the constructor from the enum, using method reference. Also, the Convertos from the enum should be private, no need for them outside.
Interface that Enums should implement in order to be persisted
public interface PersistableEnum<T> {
/** A mapping from an enum value to a type T (usually a String, Integer etc).*/
T getCode();
}
The abstract converter will use a Function in order to cover convertToEntityAttribute transformation
#Converter
public abstract class AbstractEnumConverter<E extends Enum<E> & PersistableEnum<T>, T> implements AttributeConverter<E, T> {
private Function<T, E> fromCodeToEnum;
protected AbstractEnumConverter(Function<T, E> fromCodeToEnum) {
this.fromCodeToEnum = fromCodeToEnum;
}
#Override
public T convertToDatabaseColumn(E persistableEnum) {
return persistableEnum == null ? null : persistableEnum.getCode();
}
#Override
public E convertToEntityAttribute(T code) {
return code == null ? null : fromCodeToEnum.apply(code);
}
}
The enum will implement the interface (I am using lombok for the getter) and create the converted by using a constructor
that receives a Function, I pass the ofCode using method reference. I prefer this instead of working with java.lang.Class or using reflection, I have more freedom in the enums.
#Getter
public enum CarType implements PersistableEnum<String> {
DACIA("dacia"),
FORD("ford"),
BMW("bmw");
public static CarType ofCode(String code) {
return Arrays.stream(values())
.filter(carType -> carType.code.equalsIgnoreCase(code))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("Invalid car type code."));
}
private final String code;
CarType(String code) {
this.code = code;
}
#Converter(autoApply = true)
private static class CarTypeConverter extends AbstractEnumConverter<CarType, String> {
protected CarTypeConverter () {
super(CarType::ofCode);
}
}
}
4.In the entity you just have to use the enum type and it will save it's String code.
#Column(name = "CAR_TYPE")
private CarType workflowType;
If you don't mind reflection, this works. Credit to another SO answer inline.
abstract class EnumTypeConverter<EnumType,ValueType> implements AttributeConverter<EnumType, ValueType> {
private EnumType[] values
#Override
ValueType convertToDatabaseColumn(EnumType enumInstance) {
return enumInstance ? enumInstance.getProperty(getValueColumnName()) : null
}
#Override
EnumType convertToEntityAttribute(ValueType dbData) {
if(dbData == null){
return null
}
EnumType[] values = getValues()
EnumType rtn = values.find {
it.getProperty(getValueColumnName()).equals(dbData)
}
if(!rtn) {
throw new IllegalArgumentException("Unknown ${values.first().class.name} value: ${dbData}")
}
rtn
}
private EnumType[] getValues() {
if(values == null){
Class cls = getTypeParameterType(getClass(), EnumTypeConverter.class, 0)
Method m = cls.getMethod("values")
values = m.invoke(null) as EnumType[]
}
values
}
abstract String getValueColumnName()
// https://stackoverflow.com/a/59205754/3307720
private static Class<?> getTypeParameterType(Class<?> subClass, Class<?> superClass, int typeParameterIndex) {
return getTypeVariableType(subClass, superClass.getTypeParameters()[typeParameterIndex])
}
private static Class<?> getTypeVariableType(Class<?> subClass, TypeVariable<?> typeVariable) {
Map<TypeVariable<?>, Type> subMap = new HashMap<>()
Class<?> superClass
while ((superClass = subClass.getSuperclass()) != null) {
Map<TypeVariable<?>, Type> superMap = new HashMap<>()
Type superGeneric = subClass.getGenericSuperclass()
if (superGeneric instanceof ParameterizedType) {
TypeVariable<?>[] typeParams = superClass.getTypeParameters()
Type[] actualTypeArgs = ((ParameterizedType) superGeneric).getActualTypeArguments()
for (int i = 0; i < typeParams.length; i++) {
Type actualType = actualTypeArgs[i]
if (actualType instanceof TypeVariable) {
actualType = subMap.get(actualType)
}
if (typeVariable == typeParams[i]) return (Class<?>) actualType
superMap.put(typeParams[i], actualType)
}
}
subClass = superClass
subMap = superMap
}
return null
}
}
Then in the entity class:
enum Type {
ATYPE("A"), ANOTHER_TYPE("B")
final String name
private Type(String nm) {
name = nm
}
}
...
#Column
Type type
...
#Converter(autoApply = true)
static class TypeConverter extends EnumTypeConverter<Type,String> {
String getValueColumnName(){
"name"
}
}
This is written in groovy, so you'll need some adjustments for Java.

How to use Comparable<T>?

I have the following interface
public interface Identifiable {
public Comparable<?> getIdentifier();
}
And an implementing class
public class Agreement implements Identifiable {
private Long id;
public Comparable<Long> getIdentifier() {
return id;
}
}
EDIT: Note that there may be other implementations with different types of identifiers.
Now I would like to, yes, compare the comparables:
// Agreement a;
// Agreement b;
...
if (a.getIdentifier().compareTo(b.getIdentifier()) {
...
But the compareTo gives me the following compiler error:
The method compareTo(Long) in the type Comparable<Long> is not applicable for the arguments (Comparable<Long>)
How is this interface supposed to be used with Generics?
Comparable<T> is meant to be used as an upper bound for a generic parameter:
public interface Identifiable<T extends Comparable<T>> {
public T getIdentifier();
}
public class Agreement implements Identifiable<Long> {
private final Long id;
public Long getIdentifier() {
return id;
}
}
This forces the return type to be a T, not just something that can be compared to a T.
Your code is inherently unsafe.
To understand why, consider the following code:
class Funny implements Comparable<Long> { ... }
class Funnier implements Identifiable {
public Comparable<Long> getIdentifier() {
return new Funny();
}
}
Identifiable<Funny> funnier;
funnier.getIdentifier().compareTo(funnier.getIdentifier());
// You just tried to pass a Funny to compareTo(Long)

Categories

Resources