im trying to realize simple database save logic using java generics in springboot. I create an utility interface with generic which I extend in another interface and implement in class. in classes which use database access I want extend an abstract class with generic which autowires my utility interface. is there any chance to realize this logic?
Main interface:
public interface UtilityService<T> {
T add(T entity);
T getById(long id);
T removeById(long id);
List<T> index();
}
–
public interface FoodService extends UtilityService<Food> {
Food changeQuantity(long id, int quantity);
}
–
Logic I want to realize:
#Component
public abstract class DatabaseSaver<C> {
private UtilityService<C> saver;
#Autowired
public void setSaver (UtilityService<C> saver) {
this.saver = saver;
}
public void save(C c){
saver.add(c);
}
}
–
public class SimpleClass extends DatabaseSaver<Food>{
public void dosmth(Food f){
super.save(f);
}
}
I have a multi level class structure and want to pass their implementation to a function that can call functions on them, but I get an Incompatible equality constraint: Test.SubDTO2 and Test.SubDTO error.
Here is the code:
public class Test {
abstract class DTO { }
class SubDTO extends DTO implements Interf{ }
class SubDTO2 extends DTO implements Interf{ }
class DAO<T extends DTO> { }
interface Interf { }
static DAO<SubDTO> daoImpl1;
static DAO<SubDTO2> daoImpl2;
public static void main(String... args) {
func(Arrays.asList(daoImpl1, daoImpl2)); // <- error is in this line
}
static <T extends DTO & Interf> void func(List<DAO<T>> arg) {
}
}
A more detailed example on what I try to achieve:
public class Test {
abstract class DTO {
abstract void func1();
}
class SubDTO extends DTO implements Interf{
#Override
public void func2() {
// comes from Interf
}
#Override
public void func1() {
// comes from DTO
}
}
class SubDTO2 extends DTO implements Interf{
#Override
public void func2() {
// comes from Interf
}
#Override
public void func1() {
// comes from DTO
}
}
class DAO<T extends DTO> {
public T dto() {
return null;
}
}
interface Interf {
void func2();
}
static DAO<SubDTO> daoImpl1;
static DAO<SubDTO2> daoImpl2;
public static void main(String... args) {
func(Arrays.asList(daoImpl1, daoImpl2));
}
static <T extends DTO & Interf> void func(List<? extends DAO<? extends DTO>> arg) {
arg.get(0).dto().func1(); // <- I can't call func2() here
}
}
exact error message:
[ERROR] required: java.util.List<Test.DAO<T>>
[ERROR] found: java.util.List<Test.DAO<? extends Test.DTO>>
[ERROR] reason: inference variable T has incompatible equality constraints Test.SubDTO2,Test.SubDTO
I need the list in the function func to extend DTO and also implement Interf as well, because I call certain functions on them.
Why is this happening? It works fine if I change the signature of the func and pass only one DAO, but I need it to work with multiple.
What are my options here?
I tried it with multiple java versions (1.8+), all the same.
Your function should be declared like this:
static <T extends DTO & Interf> void func(List<DAO<? extends T>> arg) {
Notice that I changed List<DAO<T>> to List<DAO<? extends T>>. This is because the expression Arrays.asList(daoImpl1, daoImpl2) produces a value of type
List<DAO<? extends DTO & Interf>>
(Of course, this isn't real syntax for a type in Java. There's no syntax for intersection types in Java but Java does know about them when doing type inference, and you could have these types in your code if you use var. I use this notation here just for illustrative purposes.)
If you know PECS, you'll know that this is a list of DAOs that produces DTO & Interfs/Ts, but does not consume DTO & Interfs/Ts. If you are lost at this point, please go read the PECS post - it's great. See also: Difference between <? super T> and <? extends T> in Java
The reason why it does this is quite intuitive. Imagine if DAO is just a container for a T.
static class DAO<T extends DTO> {
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
If Arrays.asList(daoImpl1, daoImpl2) had produced a list of DAO<DTO & Interf> (with no extends or super), you'd be able to call getT and setT on elements of the list! And being able to call setT is especially dangerous you see - you'd be able to do this:
// suppose arg is a List<DAO<DTO & Interf>>
arg.get(someRandomNumber).setT(new SubDTO());
What if someRandomNumber happens to be 1, and we get the second element, which is a DAO<SubDTO2>? Putting a SubDTO inside that destroys the whole type-safety of generics.
The only type-safe thing to do on elements of such a list like [daoImpl1, daoImpl2] is to use them as producers of DTO & Interfs, hence the type is marked ? extends DTO & Interf. This means that if you have any methods on DAO that takes in a T, you won't be able to call them on elements of this list*.
Also note that, just in case I was not clear, it is not the list that is only a producer - the list is both a producer and consumer of DAOs. It's just that the DAOs in the list are producers of their Ts.
* except by passing nulls.
I'm pretty new to java and not particularly sure how to initialize a generic type / child class from the 'base' class.
Essentially I have a bunch of classes that extend the abstract class BaseClass that need to be initialized and added to the instance Map if a key is not present.
The child class is re-used multiple times but is dynamically created based on the key parameter.
I would like to avoid reflection and don't mind changing the template if it's not 'the Java way'.
What I currently have:
public abstract class BaseClass<T> {
protected Map<String, T> instance = new HashMap<String, T>();
public T Get(String key) {
if (this.instance.containsKey(key)) {
return this.instance.get(key);
}
T item = new T(key); // Obviously this line errors but you get the idea
instance.put(key, item);
return item;
}
}
// Example top class which extends my base class
public class TopClass extends BaseClass<TopClass> {
public TopClass(String key) {
// Do unique initialization stuff
}
}
Since generic types are erased at runtime, you cannot do this. You can instead use a Class variable as follows:
public T Get(Class<T> clazz, String key) throws Exception {
if (this.instance.containsKey(key)) {
return this.instance.get(key);
}
T item = clazz.getDeclaredConstructor(String.class).newInstance(key);
instance.put(key, item);
return item;
}
I have another approach to this.
Have an interface MyInterface.
public interface MyIinterface{
public void doSomething();
}
Create an many implementations of this interface.
#Component
public class MyImplementation1 implements MyInterface{
#Override
public void doSomething(){
}
}
Use spring core jars in the dependency.
Annotate all the implementations with #Component.
#Component
public class MyImplementation1 implements MyInterface{
.
.
Have a method in some Util class that will get you the implementation based on a string key.
public static MyInterface getImplementation(String name){
ApplicationContext context;
return context.getBeanByName(name);
}
Forgive me if there are syntax problems. The goal of this is not to get the code perfect but to get the design.
I have an interface ITable<T>
public interface ITable<T> {
public Collection<T> getEntries();
public void add(CustomObj value);
public Collection<CustomObj> getCustomObjects();
}
that is used by two classes:
TableOne<CustomObj> and TableTwo<Pair<CustomObj, CustomObj>>
Then I have an interface that applies these tables using a function
public interface ITableFunction<T> {
public abstract Collection<ITable<?>> execute(Collection<ITable<T>> tables);
}
My dilemma occurs when I try to create a generic Abstract class
public abstract class AbstractTableFunctionCombined<T> implements ITableFunction<T>{
private boolean someBool;
public AbstractTableFunctionCombined(boolean someBool){
this.someBool = someBool;
}
#Override
public Collection<ITable<?>> execute(Collection<ITable<T>> tables){
// What i would like to do, but can't right now:
ITable<T> combinedTable;
if (someBool){
combinedTable = new TableOne();
} else {
combinedTable = new TableTwo();
}
for(ITable<T> table : tables){
combinedTable.addAll(table.getCustomObjects());
}
for(T entry : table.getEntries()){
execute(entry);
}
}
public abstract void execute(T entry);
}
The issue is that I can't guarantee that the type T is the same as the table that I'm trying to instantiate. I thought I had to create some kind of relationship from the Pair<CustomObj, CustomObj> and the regular CustomObj. I tried creating a Entry interface that these both would use, and having ITable<T> be ITable<T extends Entry> but again this runs into the same problem.
I also thought that maybe I can make the TableOne and TableTwo classes use the same Generic i.e. TableTwo<T> implements ITable<T>, but TableTwo has a hard restriction of using Pair<CustomObj, CustomObj>.
Would I have to create two separate classes: AbstractTableFunctionOne<CustomObj> and AbstractTableFunctionTwo<Pair<CustomObj, CustomObj>> ? I would like to avoid this as it would be a lot of duplicated code.
Or am I over forcing this Object oriented design? Should TableOne and TableTwo not even implement the same interface?
This Interface has some issus:
public interface ITableFunction {
public abstract execute(Collection<ITable<T>> tables);
}
You need a return type and a Generic:
public interface ITableFunction<T> {
public abstract void execute(Collection<ITable<T>> tables);
}
and return type of Method
public Collection<ITable<T>> execute(Collection<ITable<T>> tables){
..
should be Collection OR void in declaration AND implementation.
I have a fairly complicated structure, and it is not working as intended. This is what I did:
public interface ResultServiceHolder {
<M, ID extends Serializable, BO extends BusinessObject<M, ID>> ResultService<M, ID, BO> getService();
}
public enum ResultTypes implements ResultServiceHolder {
RESULT_TYPE_ONE {
#Override
public ResultOneService getService() { //unchecked conversion?
return serviceInitializer.getResultOneService();
}
},
RESULT_TYPE_TWO {
#Override
public ResultTwoService getService() { //unchecked conversion?
return serviceInitializer.getResultTwoService();
}
},
RESULT_TYPE_THREE {
#Override
public ResultThreeService getService() { //unchecked conversion?
return serviceInitializer.getResultThreeService();
}
};
protected ServiceInitializer serviceInitializer;
protected void setServiceInitializer(ServiceInitializer serviceInitializer) {
this.serviceInitializer = serviceInitializer;
}
#Component
public static class ServiceInitializer {
#Autowired
private ResultOneService resultOneService;
#Autowired
private ResultTwoService resultTwoService;
#Autowired
private ResultThreeService resultThreeService;
#PostConstruct
public void init() {
for(ResultTypes resultType : ResultTypes.values()) {
resultType.setServiceInitializer(this);
}
}
//getters
}
}
The purpose was to generalize the call based on enums, and rather, just be able to iterate on the array of enums.
for(ResultServiceHolder resultServiceHolder : ResultTypes.values()) {
if(resultServiceHolder.equals(post.getPostResultTypeCode())) {
return resultServiceHolder.getService().createResultSearchCriteriaResponse(postId);
}
}
And this is working fine and dandy. However, if I'd say
ResultTypes.RESULT_TYPE_ONE.getService().getRepository()
Then it is a BaseRepository<Object, Serializable> rather than a BaseRepository<ResultTypeOne, Long>. The method resultTypeHolder.getService() gives back ResultService<M, ID, BO>, but in the end, it becomes Object andSerializable.
What am I doing wrong? How can I retain the generic parameter types?
I'd like to add that yes, I do realize the problem is somewhere with the unchecked casting. But the services are defined as
public interface ResultTypeOneService
extends ResultService<ResultTypeOne, Long, ResultTypeOneBO> {
}
And I don't know why the types are not inferred.
EDIT: Technically, it works if I explicitly infer them:
ResultTypes.RESULT_TYPE_ONE.<ResultTypeOne, Long, ResultTypeOneBO>getService().getRepository()
But it ought to be automatic, why is it not working automatically? Am I supposed to provide it with some kind of object that contains the type? Why is the return type not enough for that?
EDIT2: The superclass of the ResultTypeOne is
#SuppressWarnings("serial")
#EntityListeners(EntityListener.class)
#MappedSuperclass
public abstract class EntityBase implements Serializable {
But it is not mapped anywhere in the bounds.
EDIT3: A big thank you to #Radiodef! The theoretic solution ended up to be the following, and would work perfectly fine:
public interface ResultServiceHolder<M, ID extends Serializable, BO extends BusinessObject<M, ID>> {
ResultService<M, ID, BO> getService();
}
public abstract class ResultTypes<M, ID extends Serializable, BO extends BusinessObject<M, ID>>
implements ResultServiceHolder<M, ID, BO> {
public static ResultTypes<?, ?, ?>[] values() {
return new ResultTypes<?, ?, ?>[] {RESULT_ONE, RESULT_TWO, RESULT_THREE};
}
public static final ResultTypes<ResultOne, Long, ResultOneBO> RESULT_ONE = new ResultTypes<ResultOne, Long, ResultOneBO>("Result One") {
#Override
public ResultOneService getService() {
return serviceInitializer.resultOneService;
}
};
public static final ResultTypes<ResultTwo, Long, ResultTwoBO> RESULT_TWO = new ResultTypes<ResultTwo, Long, ResultTwoBO>("Result Two") {
#Override
public ResultTwoService getService() {
return serviceInitializer.resultTwoService;
}
};
public static final ResultTypes<ResultThree, Long, ResultThreeBO> RESULT_THREE = new ResultTypes<ResultThree, Long, ResultThreeBO>("Result Three") {
#Override
public ResultThreeService getService() {
return serviceInitializer.resultThreeService;
}
};
protected String name;
protected ServiceInitializer serviceInitializer;
private ResultTypes(String name) {
this.name = name;
}
protected void setServiceInitializer(ServiceInitializer serviceInitializer) {
this.serviceInitializer = serviceInitializer;
}
#Component
static class ServiceInitializer {
#Autowired
private ResultOneService resultOneService;
#Autowired
private ResultTwoService resultTwoService;
#Autowired
private ResultThreeService resultThreeService;
#PostConstruct
public void init() {
for (ResultTypes resultType : ResultTypes.values()) {
resultType.setServiceInitializer(this);
}
}
}
}
I think because of how lengthy the solution becomes, I'll stick with the enum approach, and just accept this loss of bounds. I lose more by having to add my own values() implementation than I gain from enforcing these bounds. However, this is an interesting theoretical exercise, and thank you again for your help.
Okay, first you need to understand why what you're doing is probably not what you think it's doing. Let's look at a simpler example.
interface Face {
<T> List<T> get();
}
What you have there is a generic method, get. A generic method's type parameter depends on what is supplied by the call site. So for example like this:
Face f = ...;
// this call site dictates T to be Number
List<Number> l = f.<Number>get();
When you override it like
class Impl implements Face {
#Override
public List<String> get() { return ...; }
}
This is something you are able to do (only because of erasure) but you probably shouldn't. It's only allowed for backwards compatibility to non-generic code. You should listen to the warning and not do it. Doing it means that for example I can still come along and dictate it to return something else:
Face f = new Impl();
// now I've caused heap pollution because you
// actually returned to me a List<String>
List<Number> l = f.<Number>get();
This is why there is an unchecked conversion.
What you probably meant is to use a generic interface declaration:
interface Face<T> {
List<T> get();
}
Now the argument to T depends on the type of the object reference.
Face<Number> f = ...;
// get must return List<Number>
List<Number> l = f.get();
We can implement it like
class Impl implements Face<String> {
#Override
public List<String> get() { return ...; }
}
Additionally, you cannot access covariant return types on an enum. When you override methods on an enum constant, its class is anonymous. An anonymous class has no name and cannot be referred to. Therefore the programmer cannot know its covariant return type to use it. Furthermore, an enum cannot declare generic type parameters. So what you are wanting to do is simply impossible with enum.
You can use a class with public static final instances to simulate a generic enum:
public abstract class SimEnum<T> implements Face<T> {
public static final SimEnum<Number> A = new SimEnum<Number>() {
#Override
public List<Number> get() { return ...; }
};
public static final SimEnum<String> B = new SimEnum<String>() {
#Override
public List<String> get() { return ...; }
};
private SimEnum() {}
public static SumEnum<?>[] values() {
return new SimEnum<?>[] { A, B };
}
}
Otherwise you need to drastically change your idea.
Maybe use an interface/abstract class instead of an enum?
Enums cannot have type parameters but classes and interfaces can.
For example...
Interfaces
Entity.java
The "thing" interface...
import java.io.Serializable;
public interface Entity<K extends Serializable> {
// TODO: Put entity type things here!
// for example, things like "K getId();"
// You may want an abstract base class for this interface that all Entitys extend
}
Repository.java
Does CRUD stuff with things...
import java.io.Serializable;
public interface Repository<K extends Serializable, V extends Entity<K>> {
V getValue(K key);
// Other CRUD stuff
}
Service.java
A Service is responsible for doing stuff with things...
public interface Service<K, V> {
// Could have an abstract service class that has a repository and implements this for you...
V get(K key);
// Other "generic service" type stuff
}
Solid Classes
Entity1.java
Solid base class with String key...
public class Entity1 implements Entity<String> {
// TODO implement Entity stuff...
}
Entity2.java
Solid base class with Integer key...
public class Entity2 implements Entity<Integer> {
// TODO implement methods...
}
Entity1Service.java
Solid Entity1 Service
public class Entity1Service implements Service<String, Entity1> {
// Would not have to implement this if you extended an abstract base Service class
#Override
public Entity1 get(String key) {
return null;
}
}
Entity2Service.java
Solid Entity2 Service
public class Entity2Service implements Service<Integer, Entity2> {
// Wouldn't need this if you had abstract Service class either...
#Override
public Entity2 get(Integer key) {
return null;
}
}
ServiceHolder.java
Not an enum, but an interface - you could add methods to set the "service" from spring or something here...
import java.io.Serializable;
public abstract class ServiceHolder<K extends Serializable, V, S extends Service<K, V>> {
public static final ServiceHolder<String, Entity1, Entity1Service> ENTITY_1_SERVICE = new ServiceHolder<String, Entity1, Entity1Service>() {};
public static final ServiceHolder<Integer, Entity2, Entity2Service> ENTITY_2_SERVICE = new ServiceHolder<Integer, Entity2, Entity2Service>() {};
private S service;
private ServiceHolder() {
}
public S getService() {
return service;
}
public void setService(S service) {
this.service = service;
}
}
The interesting bit
I think this is the sort of thing you wanted, please let me know if I misunderstood...
public class PleaseCompile {
public static void main(String[] args) {
Entity1 solid1 = ServiceHolder.ENTITY_1_SERVICE.getService().get("[KEY]");
Entity2 solid2 = ServiceHolder.ENTITY_2_SERVICE.getService().get(42);
...
}
}
Hope this helps...
You cannot do what you want to do.
List<String> and List<Integer> face type erasure at runtime.
And so do your enum-mapped getService() functions.
Everything related to types for generics is validated at compile-time.