I would like to create a factory, but it's not simple with Spring and again I'm lost in space :p
This is what i would like to do.
I have an abstract class which implements multiple interface (Runnable and some personal interfaces)
public abstract class AbstractDocMan implements Runnable, DocMan {
protected AbstractDocUnit docUnit;
// some attributes
// some getter & setter
}
I have some classes which extends from this abstract class, i will call them : W, S & E :p
And some classes for the Abstract attribute (docUnit) called : WD for W, SD for S and ED for E :)
Now considering a parameter, i would like to instantiate the good class in my main controller. I would like a generic code, but working with specific class considering the good process.
Something like that.
#Component("mainVm")
#Scope("prototype")
public class MainVm {
#Autowired
private DocManFactory docManFactory;
// ???
private AbstractDocMan docMan;
...
public void setProcess(String myProcess) {
docMan = docManFactory.getDocMan(myProcess);
}
}
For moment, i have a factory defined strangely. It is working but i don't think it's a good practice :
public class DocManFactory {
#Autowired
private S s;
#Autowired
private W w;
#Autowired
private E e;
#Autowired
private SD sd;
#Autowired
private WD wd;
#Autowired
private ED ed;
public AbstractDocMan getDocMan(String myProcess) {
AbstractDocMan adm = null;
if ("S".equals(myProcess)) {
s.setDocUnit(sd);
adm = s;
} else if ("W".equals(myProcess)) {
w.setDocUnit(wd);
adm = w;
} else if ("E".equals(myProcess)) {
e.setDocUnit(ed);
adm = e;
}
return adm;
}
}
So my questions :
- How to inject dynamically the good docUnit in the factory ? cause here all object are instantiate (s,e,w,sd,ed,wd) zzz
- Is there a way to annotate the attribute in main controller ?
So...How to do a good factory with Spring (v3.1.1).
Thank you.
I think generics and a Map are the solutions here.
Your instinct is correct: this implementation is far too brittle. Start with this:
public DocManFactory {
// You can inject or hard wire these
private static final Map<String, AbstractDocMan> INSTANCES;
public static AbstractDocMan getDocMan(String processName, Process process) {
AbstractDocMan docMan = INSTANCES.get(processName);
process.setDocUnit(docMan);
return docMan;
}
}
Generics can help if the Process class that I assumed varies.
Related
I'm working on code that has an ever increasing amount of implementations for an interface VendorService. Right now, where these services are used, we autowire them all in the constructor, leading to long lists of dependencies. Is there a preferred way to handle dependencies when a single interface is repeatedly used?
Current approach:
private final VendorService xVendorService;
private final VendorService yVendorService;
private final VendorService zVendorService;
...
#Autowired
public VendorDelegateService(XVendorService xVendorService,
YVendorService yVendorService,
ZVendorService zVendorService,
...) {
this.xVendorService = xVendorService;
this.yVendorService = yVendorService;
this.yVendorService = yVendorService;
...
}
public void doSomething(VendorId vendorId) {
if (vendorId = VendorId.X) {
xVendorService.doSomething();
} else if (vendorId = VendorId.Y) {
yVendorService.doSomething();
} else if (vendorId = VendorId.Z) {
zVendorService.doSomething();
}
...
}
Clearly this is very verbose and requires updating whenever a new implementation of the interface is created.
An alternative is getting the Bean from the ApplicationContext, something like:
private final ApplicationContext context;
#Autowired
public VendorDelegateService(ApplicationContext context) {
this.context = context;
}
public void doSomething(VendorId vendorId) {
context.getBean(VendorService.class, vendorId.name()).doSomething();
}
This wouldn't require another if/else bracket with every new implementation, but it's obtuse and doesn't feel correct. This logic could of course be abstracted away in its own class to lessen that problem.
Which of these is more idiomatic in Spring and Java? Are there any other approaches I haven't considered?
I feel it is a matter of preference whether there is an idiomatic way for this, but what I suggest is the following solution:
Create an interface for all the services, we can call this VendorService:
public interface VendorService {
void doSomething();
VendorId getVendorId();
}
Now we would want to implement this interface for all the services, as an example this can be done like this for XVendorService:
#Service
public XVendorService implements VendorService {
private VendorId vendorId = ....
#Override
public void doSomething() {
...
}
#Override
public VendorId getKey() {
return vendorId;
}
}
Now for the VendorDelegateService we can do something like this:
#Service
public class VendorDelegateService {
private Map<VendorId, VendorService> services = new HashMap<>();
#Autowired
public AllServices(Set<? extends VendorService> serviceSet) {
serviceSet.stream().forEach(service -> services.put(service.getVendorId(), service));
}
public void doSomething(VendorId vendorId) {
if (services.containsKey(vendorId)) {
services.get(vendorId).doSomething();
}
}
}
Please note that with Set<? extends VendorService> serviceSet all the services will be autowired automatically. By creating a map afterwards, we are able to dispatch our request to every service based on its vendorKey.
There exist following classes
class Entity{
}
class Dto{
}
public abstract class BaseMapper<E extends Entity, D extends Dto>{
}
And several sepcific implementation of mappers like:
FooMapper extends BaseMapper<Foo, FooDto>{
}
FeeMapper extends BaseMapper<Fee, FeeDto>{
}
No I want to integrate some "Wrapper" which does a bit more than normal mapping of the data, because I got a new concept/issue
#Component
public final class RevMapper<ENTITY extends Entity, DTO extends Dto> {
private BaseMapper<ENTITY, DTO> baseMapper;
#Autowired
public <MAPPER extends BaseMapper<ENTITY, DTO>> RevMapper(MAPPER mapper) {
this.baseMapper = mapper;
}
public List<RevDto<DTO>> toDto(final List<Rev<ENTITY>> revList) {
for(Rev<ENTITY> rev: revList){
...
baseMapper.toDto(rev.getEntity(), true);
}
...
}
}
And include it in my service like:
#Autowired
private RevMapper<Foo, FooDto> fooRevMapper;
The problem now is:
Parameter 0 of constructor in com.test.package.RevMapper required a single bean, but 2 were found:
- FooMapper
- FeeMapper
Spring doesn't know which to take. And yeah what I know is about the type erasure in generics. So basically after compile the application just know that there is a
RevMapper<Entity,Dto>
but not which type it is specifically. How could I tell Spring to insert the right component, or how would you handle this problem. I do not want to write the same lines of code for each type of Mapper....
The solution I can think of is not as time consuming than creating many many subclasses.
First make the RevMapper not a #Component and then create a class like follows:
#Configuration
public final class Mappers{
private final FooMapper fooMapper;
private final FeeMapper feeMapper;
#Autowired
public Mappers(FooMapper fooMapper, FeeMapper feeMapper){
this.fooMapper = fooMapper;
this.feeMapper = feeMapper;
}
#Bean
public RevMapper<Foo, FooDto> fooRevMapper(){
return new RevMapper(fooMapper);
}
#Bean
public RevMapper<Fee, FeeDto> feeRevMapper(){
return new RevMapper(feeMapper);
}
}
It's no more than just creating a method for every different RevMapper you want to provide.
My Spring Boot application contains several #KafkaListeners, and each listener performs the same steps before and after actually processing the payload: Validate the payload, check whether the event has been processed already, check whether it's a tombstone (null) message, decide whether processing should be retried in case of failure, emit metrics, etc.
These steps are currently implemented in a base class, but because the topics passed to #KafkaListener must be constant at runtime, the method annotated with #KafkaListener is defined in the subclass, and does nothing but pass its parameters to a method in the base class.
This works just fine, but I wonder if there's a more elegant solution. I assume my base class would have to create a listener container programmatically, but after a quick look at KafkaListenerAnnotationBeanPostProcessor, it seems to be quite involved.
Does anyone have any recommendadtions?
Having stumbled upon this question while looking to implement something similar, I first started with Artem Bilan's answer. However this did not work because annotations by default are not inherited in child classes unless they are themselves annotated with #Inherited. Despite this there may yet be a way to make an annotation approach work and I will update this answer if and when I get it to work. Thankfully though I have achieved the desired behavour using programtic registration of the Kafka listeners.
My code is something like the following:
Interface:
public interface GenericKafkaListener {
String METHOD = "handleMessage";
void handleMessage(ConsumerRecord<String, String> record);
}
Abstract Class:
public abstract class AbstractGenericKafkaListener implements GenericKafkaListener {
private final String kafkaTopic;
public AbstractGenericKafkaListener(final String kafkaTopic) {
this.kafakTopic = kafkaTopic;
}
#Override
public void handleMessage(final ConsumerRecord<String, String> record) {
//do common logic here
specificLogic(record);
}
protected abstract specificLogic(ConsumerRecord<String, String> record);
public String getKafkaTopic() {
return kafkaTopic;
}
}
We can then programtically register all beans of type AbstractGenericKafkaListener in a KafkaListenerConfigurer:
#Configuration
public class KafkaListenerConfigurataion implements KafkaListenerConfigurer {
#Autowired
private final List<AbstractGenericKafkaListener> listeners;
#Autowired
private final BeanFactory beanFactory;
#Autowired
private final MessageHandlerMethodFactory messageHandlerMethodFactory;
#Autowired
private final KafkaListenerContainerFactory kafkaListenerContainerFactory;
#Value("${your.kafka.consumer.group-id}")
private String consumerGroup;
#Value("${your.application.name}")
private String service;
#Override
public void configureKafkaListeners(
final KafkaListenerEndpointRegistrar registrar) {
final Method listenerMethod = lookUpMethod();
listeners.forEach(listener -> {
registerListenerEndpoint(listener, listenerMethod, registrar);
});
}
private void registerListenerEndpoint(final AbstractGenericKafkaListener listener,
final Method listenerMethod,
final KafkaListenerEndpointRegistrar registrar) {
log.info("Registering {} endpoint on topic {}", listener.getClass(),
listener.getKafkaTopic());
final MethodKafkaListenerEndpoint<String, String> endpoint =
createListenerEndpoint(listener, listenerMethod);
registrar.registerEndpoint(endpoint);
}
private MethodKafkaListenerEndpoint<String, String> createListenerEndpoint(
final AbstractGenericKafkaListener listener, final Method listenerMethod) {
final MethodKafkaListenerEndpoint<String, String> endpoint = new MethodKafkaListenerEndpoint<>();
endpoint.setBeanFactory(beanFactory);
endpoint.setBean(listener);
endpoint.setMethod(listenerMethod);
endpoint.setId(service + "-" + listener.getKafkaTopic());
endpoint.setGroup(consumerGroup);
endpoint.setTopics(listener.getKafkaTopic());
endpoint.setMessageHandlerMethodFactory(messageHandlerMethodFactory);
return endpoint;
}
private Method lookUpMethod() {
return Arrays.stream(GenericKafkaListener.class.getMethods())
.filter(m -> m.getName().equals(GenericKafkaListener.METHOD))
.findAny()
.orElseThrow(() ->
new IllegalStateException("Could not find method " + GenericKafkaListener.METHOD));
}
}
How about this:
public abstract class BaseKafkaProcessingLogic {
#KafkaHandler
public void handle(Object payload) {
}
}
#KafkaListener(topics = "topic1")
public class Topic1Handler extends BaseKafkaProcessingLogic {
}
#KafkaListener(topics = "topic2")
public class Topic2Handler extends BaseKafkaProcessingLogic {
}
?
I needed the same functionality and came up with solution close to Artem Bilan answer. Yes, #KafkaHandler annotation is not inherited by the child classes but defined in interface it is. Here is the solution:
interface AbstractKafkaListener<T> {
default Class<T> getCommandType() {
TypeToken<T> type = new TypeToken<>(getClass()) {};
return (Class<T>) type.getRawType();
}
#KafkaHandler
default void handle(String message) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
T value = objectMapper.readValue(message, getCommandType());
handle(value);
}
void handle(T message);
}
The class should implement the handle method only:
#Component
#KafkaListener(topics = "my_topic")
public class KafkaListenerForMyCustomMessage implements AbstractKafkaListener<MyCustomMessage> {
#Override
public void handle(MyCustomMessage message) {
System.out.println(message);
}
}
The 2 implemented methods in the interface should be private/protected but because they are in interface this cannot be done. default methods are always public. Actually, all methods defined in interface are always public.
I use this solution to dynamically parse the message from kafka (received in String) to the custom class.
getCommandType method returns the class of the T generic param. TypeToken is from Google Guava package.
I am new in spring and have to use spring annotations all through the project. I need to create a list of beans. I do not have option to use context.getBean("..") from the class where I have to create the list.
The problem is :
I have 3 classes: Processor, Reader, Writer. I have to create a list of writers inside the processor class.
This is what I am looking for : ( trying to #Autowire 'RoxourReader readerThread' and 'List writerThreads' but don't know how determine the size of the list and need to add the name as well)
package company.online.Roxour.api.operation;
{
#Component
#Scope("singleton")
public class RoxourProcessor
{
.........
private int PAYLOAD_SIZE;
private int MAX_READER_THREADS;
private int MAX_WORKER_THREADS;
#Autowired
ApplicationEnvironment applicationEnvironment;
#Autowired
RoxourUtil util;
//I wish to have something like this
#Autowired
RoxourReader readerThread
//I wish to have something like this
#Autowired
List<RoxourWriter> writerThreads;
#PostConstruct public void initialize()
{
PAYLOAD_SIZE = applicationEnvironment.getPayloadSize();
MAX_READER_THREADS = applicationEnvironment.getMaxReaderThreads();
MAX_WORKER_THREADS = applicationEnvironment.getMaxWorkerThreads();
}
..............
}
}
Reader class looks like :
package company.online.Roxour.api.operation;
{
#Component
#Scope("prototype")
public class RoxourReader extends Thread
{
.........
#Autowired
ApplicationEnvironment applicationEnvironment;
public RoxourReader( String name)
{
this.name = name;
}
..............
}
}
And the writer class looks like :
package company.online.Roxour.api.operation;
{
#Component
#Scope("prototype")
public class RoxourWriter extends Thread
{
.........
#Autowired
ApplicationEnvironment applicationEnvironment;
public RoxourWriter( String name)
{
this.name = name;
}
..............
}
}
context.xml has:
<!-- Scans within the base package of the application for #Components to configure as beans -->
<context:component-scan base-package="company.online.Roxour.api"/>
According to current implementation, this is the way we are creating the treads:
private void createAllThreads()
{
readerThread = new RoxourReader( "Reader " + 1 );
writerThreads= new RoxourWriter[ MAX_WORKER_THREADS ];
for ( int i = 0; i < MAX_WORKER_THREADS; i++ )
{
writerThreads[ i ] = new RoxourWriter( "Uploader " + i);
}
}
Is this possible? Please advise me a different approach with annotations otherwise.
Thanks
When you use a IoC framework like Spring, you leave the task of bean creation to Spring. So you shouldn't use new keyword, this is made by Spring automatically.
Instead you should get your beans through context.getBean("beanname") or
injecting the bean with #autowired.
Here there is an example or Spring with threads (There is 3 good examples)
http://www.mkyong.com/spring/spring-and-java-thread-example/
And here there is the definition of task executors.
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html
To begin with,
public class RoxourReader extends Thread
{
is not a good idea, because you are not extending the Thread behavior. Instead make it
public class RoxourReader implements Runnable
{
and when you use the keyword new to create an object, then Spring is not actually managing it.
So change the lines
new RoxourReader... &
new RoxourWriter
to Autowired (or) getBeans methods like
private void createAllThreads()
{
readerThread = getReaderBean("readerBeanName");
writerThreads= new Runnable[MAX_WORKER_THREADS];
for ( int i = 0; i < MAX_WORKER_THREADS; i++ )
{
writerThreads[ i ] = getWriterBean("Uploader " + i);
}
}
And your getBeans methods would look like,
public Runnable getReaderBean(){
Runnable obj= applicationContext.getBean("RoxourReader");
return obj;
}
public Runnable getWriterBean(){
Runnable obj= applicationContext.getBean("RoxourWriter");
return obj;
}
Since your scope is Prototype for both reader and writer beans already, you will get a new bean instance.
I have an application with 3 layers:
App <--> Graph <--> Couchbase
I'm trying to test the GraphConnector by mocking the couchbase layer and "replacing" it with a very basic in-memory graph implementation, using the same approach demonstrated in the JMockit tutorial.
This is my test class (pardon the poor indentation, didn't get the hang of it yet):
public class GraphConnectorTest {
public static final class MockCouchbase extends MockUp<ICouchConnector> {
private Map<String, CouchEntry> couch;
#Mock
public void $clinit() {
couch = new HashMap<String, CouchEntry>();
}
#Mock
public void put(CouchEntry entry) {
couch.put(entry.getKey(), entry);
}
#Mock
public CouchEntry get(String key) {
return couch.get(key);
}
}
GraphConnectorImpl graph = new GraphConnectorImpl();
#BeforeClass
public static void setUpClass() {
new MockCouchbase();
}
#Test
public void testPost() throws Exception {
GraphNode node = new GraphNode(GraphNodeType.DOMAIN, "alon.com");
graph.post(node);
GraphNode retNode = graph.getSingleNode(node.getValue(), node.getType());
assertEquals(node.getValue(), retNode.getValue());
assertEquals(node.getType(), retNode.getType());
}
}
And here is my class under test:
public class GraphConnectorImpl implements IGraphConnector {
private static ICouchConnector couch = new CouchConnectorImpl(); // <-- Basic implementation which I don't want the test to execute
#Override
public void post(GraphNode node) {
CouchEntry entry = new CouchEntry(node.getValue(), JsonDocument.create(node.getValue()));
couch.put(entry);
}
#Override
public GraphNode getSingleNode(String nodeName, GraphNodeType nodeType) {
return new GraphNode(nodeType, couch.get(nodeName).getKey());
}
}
For some reason, the class MockCouchbase that I created within the test class isn't automatically bound to the private field ICouchConnector couch of the tested class, as shown in the tutorial. Instead, the real implementation is called, which is obviously undesirable.
If I remove the reference to the real implementation, I just get a good ol' NullPointerException.
I tried playing with the #Tested and #Injectable annotations but to no avail.
Solving my own question.
The problem with the way I wrote the class under test was explicitly invoking the constructor of the real implementation. I'll be surprised if any mocking framework can "bypass" that.
Instead, I should've created a constructor that gets ICouchConnector as one of its arguments, e.g. use dependency injection properly.
public class GraphConnectorImpl implements IGraphConnector {
private static ICouchConnector couch;
public GraphConnectorImpl(ICouchConnector connector) {
couch = connector;
}
// Rest of class...
}
JMockit will then attempt to find a constructor that corresponds to the fields annotated #Tested and #Injectable in the test class.
public class GraphConnectorTest {
#Tested
GraphConnectorImpl graph;
#Injectable
ICouchConnector couch;
// Rest of class...
}