I'm working on building a library to help you bootstrap the development of a Java API. The premise is, you can have your controllers implement interfaces like IGetController<SomeEntity>
or IListController<SomeEntity>
. These interfaces have default
methods to implement their endpoint, and use a service factory to get the appropriate service to do the bulk of the work. These services are also interfaces, and have default
methods which get a repository (by calling getRepository
on the IBaseService
they extend). There's a lot of "magic" going on here to inspect the genericInterfaces
on the class, and then getting the type arguments to determine what entity we're working with.
The problem I'm having is consolidating my factories. Take a look at these two factory classes:
GetServiceFactory
:
package apibuilder.service.factory;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import apibuilder.entity.BaseEntity;
import apibuilder.service.IGetService;
public class GetServiceFactory {
private static final Map<Type, IGetService<? extends BaseEntity>>
registrationMap = new HashMap<>();
public static <T extends BaseEntity> IGetService<T> getService(final Type entityType) {
if (registrationMap.containsKey(entityType)) {
//noinspection unchecked
return (IGetService<T>) registrationMap.get(entityType);
}
return null;
}
public static <T extends BaseEntity> void registerServices(final IGetService<T>[] services) {
for (IGetService<T> service : services) {
Type entityType = ((ParameterizedType) service.getClass().getGenericInterfaces()[0])
.getActualTypeArguments()[0];
registrationMap.put(entityType, service);
}
}
}
ListServiceFactory
:
package apibuilder.service.factory;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import apibuilder.entity.BaseEntity;
import apibuilder.service.IListService;
public class ListServiceFactory {
private static final Map<Type, IListService<? extends BaseEntity>>
registrationMap = new HashMap<>();
public static <T extends BaseEntity> IListService<T> getService(final Type entityType) {
if (registrationMap.containsKey(entityType)) {
//noinspection unchecked
return (IListService<T>) registrationMap.get(entityType);
}
return null;
}
public static <T extends BaseEntity> void registerServices(final IListService<T>[] services) {
for (IListService<T> service : services) {
Type entityType = ((ParameterizedType) service.getClass().getGenericInterfaces()[0])
.getActualTypeArguments()[0];
registrationMap.put(entityType, service);
}
}
}
As you can see, they're nearly identical. They create a map to get the proper service per entity, and then have methods to build the map, and get a service from the map. I feel like these can be consolidated into some sort of BaseServiceFactory
, but I'm having a hard time actually pulling it off.