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);
}
}
Related
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);
}
Is there a way to setup the following construct in JAVA:
having a common interface or base class
having a static public field declared by the common interface
each model implementing the common interface should have its own static field (not one shared instance for all models)
Detailed explanation:
I'm working with ORMLite and I need to refresh the ForeignCollections of my models after deserialization. For doing this I need to have a reference to my DAO from the models, which I don't want to.
So, I came up with the following concept:
keep a static field in each of the models of the following Interface:
public interface SerializableObserver {
void onAfterDeserialization(Object object);
}
in my implementation of private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException after reading in all ivars i'am calling the onAfterDeserialization-Method of the static field i'am holding in the model.
In the Dao, I'm setting the static field of the model. So when the deserialization is finished, a method in my Dao is called. Where i can finally refresh the ForeignCollection so it's still valid after deserialization.
So what I'm looking for is some sort of way to make this whole approach a bit more generic so, I don't have to implement this behavior for all of my 20 Models.
And finally, this is going to be an Android-App. so no fancy Java-8 things.
I would use another class that maps Model classes to SerializableObserver implementations.
For example,
DeserializerMap:
public enum DeserializerMap {
INSTANCE;
private Map<Class<? extends Model>, SerializableObserver> modelObserverMap = new HashMap<>();
public void registerSerializableObserver(Class<? extends Model> modelClass, SerializableObserver serializableObserver) {
modelObserverMap.put( modelClass, serializableObserver );
}
public void deregisterSerializableObserver(Class<? extends Model> modelClass) {
modelObserverMap.remove( modelClass );
}
public SerializableObserver getSerializableObserver(Class<? extends Model> modelClass){
return modelObserverMap.get( modelClass );
}
}
Model class:
public class ModelClass implements Model{
private int id;
public ModelClass(int id) {
this.id = id;
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException{
ois.defaultReadObject();
DeserializerMap.INSTANCE.getSerializableObserver( this.getClass() ).
onAfterDeserialization( this );
}
}
The "Model" interface just extends Serializable and is used in DeserializerMap, but you can just get rid of the interface and use Class<? extends Object> instead of Class<? extends Model> in DeserializerMap,
Model:
public interface Model extends Serializable{
}
DAO Class:
public class DAOClass {
public DAOClass(){
SerializableObserver serializableObserver = new SerializableObserver() {
#Override
public void onAfterDeserialization(Object object) {
System.out.println("After deserialization");
anotherMethod();
}
};
DeserializerMap.INSTANCE.registerSerializableObserver( ModelClass.class, serializableObserver );
}
public void anotherMethod(){
System.out.println("another method");
}
}
if you don't want to do anything additional than just call DAOClass method then you can map ModelClass with DAOClass classes, but I would recommend using DAO just for communicating with your persistence system and register mappings in your main class and not in DAOClass constructor.
Without understanding the details I can offer the following:
Use an Interface to define commonly required behaviour and then a generic abstract base class to define a common structure is something you should consider.
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'm trying to create a "CRUD manager" class, performing database operations of objects that extend an abstract superclass I created. The abstract class is fairly simple:
public abstract class IndexedEntity() {
protected Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
if(id == null)
this.id = id;
else throw new UnsupportedOperationException
("The ID cannot be changed once it was set.");
}
}
Now I have a couple of classes that extend this IndexedEntity, and these classes represent my business entities: Car, Customer, Lease
Instead of creating a CRUD manager for each business entity, I figured I'd try creating a common CRUD class that supports their common superclass.
How do I create a generic class, that takes a type parameter when being constructed, and that type parameter is limited to certain types - those who inherit from IndexedEntity?
Something like:
public interface ICrudManager<IndexedEntity> {
public void add(IndexedEntity e);
public IndexedEntity get(long id);
public void update(IndexedEntity e);
public void delete(IndexedEntity e);
public List<IndexedEntity> getAll();
}
Is it possible in Java? Or, is there anything wrong about this idea / do think it's an acceptable design choice?
(I might abandon it first thing tomorrow because it may be too difficult to generalize a lot of behavior, but at the moment I'm curious how can it be done.
Use Bounded Type Parameters
public interface ICrudManager<T extends IndexedEntity> {
public void add(T e);
public IndexedEntity get(long id);
public void update(T e);
public void delete(T e);
public List<T> getAll();
}
and You can create objects like ICrudManager<Car> carManager = new CrudManagerImpl<Car>();
public interface MyInterface<T extends MyClass>
You can either change the interface line to public <T> interface ICrudManager <T exdents IndexedEntity> which will result in an compiler error if you try to insert a class that doesn't match.
If you want your system to be more dynamically you can you an abstract class with an initializer that tests the type during execution.
public abstract <T> class {
{
if(!T instanceof IndexedEntity)
throw new TypeException()
}
}
I have some classes that look like this:
MODEL
public abstract class BaseEntity<O extends Object> { ... }
public class Person extends BaseEntity<Person> { ... }
COMMAND
public abstract class BaseCommand<BE extends BaseEntity<BE>> { ... }
public class PersonCommand extends BaseCommand<Person> { ... }
SERVICE
public interface BaseService<BE extends BaseEntity<BE>> {
public BE create(BaseCommand<BE> command);
}
public interface PersonService extends BaseService<Person> { ... }
SERVICE IMPL
public abstract class BaseServiceImpl<BE extends BaseEntity<BE>> implements BaseService<BE> { }
public class PersonServiceImpl extends BaseServiceImpl<Person> implements PersonService {
public Person create(PersonCommand personCommand) { ... }
}
The PersonServiceImpl class won't compile. It's not recognizing that the create() method is implementing the create() method from the BaseService interface. Can anyone tell why PersonCommand isn't being recognized as a BaseCommand<BE> (in the parameter list)?
When overriding, method parameters are not covariant (that is, subclasses have to accept a type that the superclass also accepts, not anything narrower).
This is because people can use your PersonServiceImpl via the PersonService interface, which will accept an argument of type BaseCommand<Person> that is not necessarily a PersonCommand (imagine if you created a second class that extended BaseCommand<Person>).
If you make your method take a parameter of type BaseCommand<Person>, your code should compile correctly.