How to implement Decorator pattern in Spring Boot - java

I know how to implement and use a decorator pattern without Spring.
Because in this pattern you yourself control the process of creating components and you can perform dynamic behavior adding.
Below is an example of implementation without using Spring:
public class SimpleDecoratorApp {
public static void main(String[] args) {
SimplePrinter simplePrinter = new SimplePrinter();
Printer decorated = new UpperCasePrinterDecorator(
new AddAsterisksPrinterDecorator(simplePrinter)
);
decorated.print("hello"); // *** HELLO ***
}
}
interface Printer {
void print(String msg);
}
class SimplePrinter implements Printer {
#Override
public void print(String msg) {
System.out.println(msg);
}
}
abstract class PrinterDecorator implements Printer {
protected Printer printer;
public PrinterDecorator(Printer printer) {
this.printer = printer;
}
}
class UpperCasePrinterDecorator extends PrinterDecorator {
public UpperCasePrinterDecorator(Printer printer) {
super(printer);
}
#Override
public void print(String msg) {
String s = msg.toUpperCase();
this.printer.print(s);
}
}
class AddAsterisksPrinterDecorator extends PrinterDecorator {
public AddAsterisksPrinterDecorator(Printer printer) {
super(printer);
}
#Override
public void print(String msg) {
msg = "*** " + msg + " ***";
this.printer.print(msg);
}
}
I am interested in how to implement the same example but with the help of spring beans.
Because I don’t quite understand how to maintain flexibility in the ability to simply wrap with any number of decorators.
Because as I understand it - it will be implemented fixed in some separate component and I will have to create dozens of various separate components with the combinations of decorators I need.

I haven't really understood what is your actual problem here, but I'll try anyway.
Say you have these classes
UpperCasePrinterDecorator
LowerCasePrinterDecorator
AddAsterisksPrinterDecorator
Each of these require an instance of a Printer, which, let's say is provided as a Spring #Component. To use each decorator as Spring Bean you need to register it.
#Bean
#Qualifier("upperCase")
PrinterDecorator upperCasePrinterDecorator(final Printer printer) { // Injected automatically
return new UpperCasePrinterDecorator(printer);
}
#Bean
#Qualifier("lowerCase")
PrinterDecorator lowerCasePrinterDecorator(final Printer printer) {
return new LoweCasePrinterDecorator(printer);
}
#Bean
#Qualifier("asterisk")
PrinterDecorator addAsterisksPrinterDecorator(final Printer printer) {
return new AddAsterisksPrinterDecorator(printer);
}
You can then use the #Qualifier annotation to get the right one #Autowired
#Autowired
#Qualifier("lowerCase")
private PrinterDecorator printer;

Use a BeanPostProcessor. In this example I used P6DataSource as a decorator that wraps an existing DataSource. Using this approach, your existing code doesn't change since the interface is kept intact and #Autowire of the wrapped class works as expected.
import com.p6spy.engine.spy.P6DataSource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.scope.ScopedProxyUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import javax.sql.DataSource;
import static org.springframework.core.Ordered.LOWEST_PRECEDENCE;
#Configuration
#Order(LOWEST_PRECEDENCE)
#Slf4j
public class DataSourceBeanPostProcessor implements BeanPostProcessor {
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof DataSource
&& !ScopedProxyUtils.isScopedTarget(beanName)) {
log.debug("Decorating {} with P6Spy", bean);
return new P6DataSource((DataSource) bean);
} else {
return bean;
}
}
}

Related

How to execute 1 method of all implementations in spring

I have some classes below. Obviously, if I invoke "printMessage" in CustomAtm class, it will execute the method in PrinterFile because I declared it by #Qualifier. But I wonder Is there any way to execute both "printMessage" method in PrinterConsole and PrinterFile when I invoke it and I don't declare #Qualifier ?
Printer interface
public interface Printer {
void printMessage(String message);
}
PrinterConsole class
import org.springframework.stereotype.Component;
#Component("printerConsole")
public class PrinterConsole implements Printer {
#Override
public void printMessage(String message) {
System.out.println(message);
}
}
PrinterFile class
import org.springframework.stereotype.Component;
#Component("printerFile")
public class PrinterFile implements Printer {
Logger logger = LoggerFactory.getLogger(PrinterFile.class);
#Override
public void printMessage(String message) {
logger.info(message);
}
}
CustomAtm class
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
#Component("customAtm")
public class CustomAtm {
#Autowired
#Qualifier("printerFile")
Printer printer;
public void printCurrentMoney() {
printer.printMessage("Current ATM money is... ");
}
}
You can look up all instances that are registered as bean and implement the Printer interface:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component("customAtm")
public class CustomAtm {
#Autowired
private ApplicationContext applicationContext;
public void printCurrentMoney() {
Map<String, Printer> printers = context.getBeansOfType(Printer.class);
for(Printer printer: printers.values()){
printer.printMessage("Current ATM money is... ");
}
}
}
Method 1
Inject list of printer
#Autowired(required = false)
private List<Printer> printers;
public void printAll() {
for (Printer printer : printers) {
printer.print();
}
}
Method 2
you can define another class that combine the 2 beans
#Component("printerAdapter")
public class PrinterAdapter implements Printer {
#Autowired
#Qualifier("printerFile")
Printer printerFile;
#Autowired
#Qualifier("printerConsole")
Printer printerConsole;
#Override
public void printMessage(String message) {
printerConsole.printMessage();
printerFile.printMessage();
}
}
And in your client class inject the new printer class and use it
#Autowired
#Qualifier("printerAdapter")
Printer printer;

Non-Spring lightweight AOP without xml config for weaving annotations to methods

Need to run before and after methods on some annotations.
Not using spring, no xml. Is it possible to have some kind of AOP engine that I set from main() so that it can be invoked whenever needed? It's also OK for me to put in a method to manually call an evaluation method.
Example:
public void doThis(#RequiredSecurityRole("admin") user){
doAOPStuff();
}
before() get from the db and check if user is admin, throws Exception if it's not admin.
after() log into db the action.
How to achieve this?
You can do this yourself using the java.lang.reflex.Proxy class. It does require that the code you're proxying be defined in an interface.
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DoItYourAop {
public static void main(String[] args) {
SaysHello saysHello = new SaysHelloImpl();
InvocationHandler logger = new LoggingProxy(saysHello);
SaysHello proxy = (SaysHello) Proxy.newProxyInstance(SaysHello.class.getClassLoader(),
new Class[]{SaysHello.class}, logger);
proxy.sayHello();
}
public interface SaysHello {
void sayHello();
void sayGoodbye();
}
public static class SaysHelloImpl implements SaysHello {
#Log
#Override
public void sayHello() {
System.out.println("Says Hello");
}
#Override
public void sayGoodbye() {
System.out.println("Says Goodbye");
}
}
#Retention(RUNTIME)
#interface Log {
}
public static class LoggingProxy implements InvocationHandler {
private final Object proxied;
public LoggingProxy(Object proxied) {
this.proxied = proxied;
}
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Method proxiedMethod = proxied.getClass().getMethod(method.getName(), method.getParameterTypes());
boolean log = proxiedMethod.isAnnotationPresent(Log.class);
if (log) {
System.out.println("Before");
}
Object result = method.invoke(proxied, args);
if (log) {
System.out.println("After");
}
return result;
}
}
}

How to create a collection of objects in SpringBoot without having the database?

I am new to SpringBoot. I don't know how to create a few objects of the same type in the way that enables to use this objects later for example in the controller.
Let's say I would like to create collection/list of objects (let's say collection of Rabbits) when the application starts:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
// I would like to create here a collection
// or a list of objects (let's say collection of Rabbits)
}
}
I would like to have the possibility to use this objects later in the controller to get some information (obtained for example by index in the list).
What is the right way to keep state of my model without having a database?
Ignoring synchronization issues.
You can create a List and inject into your controllers.
or what I like to do is wrap that in a repository. This insulates you from the underlying datasource and it can be changed later.
Note that synchronization is important for this type of data structure as you can have many threads updating the repository.
package com.example.demo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#SpringBootApplication
public class Demo1Application {
public static void main(String[] args) {
SpringApplication.run(Demo1Application.class, args);
}
#Bean
public RabbitRepository rabbitRepository() {
RabbitRepository rabbitRepository = new RabbitRepository();
rabbitRepository.add("Bugs");
rabbitRepository.add("Flopsy");
return rabbitRepository;
}
public static class RabbitRepository {
private List<Rabbit> rabbits = Collections.synchronizedList(new ArrayList<Rabbit>());
public List<Rabbit> getAll() {
return rabbits;
}
public Rabbit add(String rabbitName) {
Rabbit rabbit = new Rabbit(rabbitName);
this.rabbits.add(rabbit);
return rabbit;
}
public Optional<Rabbit> findById(int id) {
return this.rabbits.stream().filter(r-> r.getId() == id).findFirst();
}
}
public static class Rabbit {
private final String name;
private final int id;
private static AtomicInteger counter = new AtomicInteger();
public Rabbit(String name) {
super();
this.name = name;
this.id = counter.incrementAndGet();
}
public String getName() {
return name;
}
public int getId() {
return this.id;
}
}
#RestController
#RequestMapping("/rabbits")
public static class RabbitController {
private final RabbitRepository repository;
public RabbitController(final RabbitRepository repository) {
this.repository = repository;
}
#GetMapping
public List<Rabbit> getAll() {
return repository.getAll();
}
#PostMapping("/{name}")
//You can also use requestparam / requestbody and probably should
public Rabbit addRabbit(#PathVariable("name") String name) {
return repository.add(name);
}
#GetMapping("/id/{id}")
public Optional<Rabbit> findById(#PathVariable("id") int id) {
return repository.findById(id);
}
}
}
Curl tests
➜ ~ curl localhost:8080/rabbits
[{"name":"Bugs","id":1},{"name":"Flopsy","id":2}]%
➜ ~ curl localhost:8080/rabbits/id/2
{"name":"Flopsy","id":2}%
➜ ~ curl -XPOST localhost:8080/rabbits/Babs
{"name":"Babs","id":3}%
➜ ~ curl localhost:8080/rabbits
[{"name":"Bugs","id":1},{"name":"Flopsy","id":2},{"name":"Babs","id":3}]%
Using spring you need to create objects in the context of spring, otherwise spring created instances can't find them. A solution can be putting them in a class annotated with #Configuration and retrieve them with the annotation #Autowired.
The annotation #Configuration:
Indicates that a class declares one or more #Bean methods and may be processed by the Spring container to generate bean definitions and service requests for those beans at runtime.
You can use it as follow:
#Configuration
public class MyConfiguration {
#Bean
public MyClass getMyClass() {
MyClass myClass = ...
...
return myClass;
}
}
#Controller
public class MyController {
#Autowired
private MyClass myClass;
public void method() {
// Use myClass instance as you like
}
}
You can also generate a standard java.util.List, but in this case is better to give a name to the bean generated, for example:
#Configuration
public class MyConfiguration {
#Bean("myname") // To give an explicit name to the List
public List getMyList() {
List myList = ...
...
return myList;
}
}
#Controller
public class MyController {
#Autowired
#Qualifier("myname") // To retrieve a List with a specific name
private List myList;
public void method() {
// Use myList instance as you like
}
}
You need something like this i guess !
#Component
public class RabbitListHolder {
private List<Rabbit> rabbits = new ArrayList<Rabbit>
public void initializeList(){
rabbits.add(new Rabbit('white', 3));
...
}
}
#Controller
public class RabbitsRessource{
#Autowired
RabbitListHolder rabbitListHolder;
...
#GetMapping("/rabbits")
public List<Rabbits> getRabbits(){
rabbitListHolder.initializeList();
return rabbitListHolder.getRabbits();
}
}

Start thread at springboot application

I want to execute a java class (which contains a java thread I want to execute) after spring boot starts. My initial code:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
And here is is the code I want to execute at start:
public class SimularProfesor implements Runnable{
// Class atributes
// Constructor
public SimularProfesor() {
//Initialization of atributes
}
#Override
public void run() {
while(true) {
// Do something
}
}
}
How can I call this thread? This is what I'm supposed to do:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
// Call thread (constructor must be executed too)
}
}
Don't mess around with threads yourself. Spring (and also plain Java) has a nice abstraction for that.
First create a bean of the type TaskExecutor in your configuration
#Bean
public TaskExecutor taskExecutor() {
return new SimpleAsyncTaskExecutor(); // Or use another one of your liking
}
Then create a CommandLineRunner (although an ApplicationListener<ContextRefreshedEvent> would also work) to schedule your task.
#Bean
public CommandLineRunner schedulingRunner(TaskExecutor executor) {
return new CommandLineRunner() {
public void run(String... args) throws Exception {
executor.execute(new SimularProfesor());
}
}
}
You could of course make also your own class managed by spring.
Advantage of this is that Spring will also cleanup the threads for you and you don't have to think about it yourself. I used a CommandLineRunner here because that will execute after all beans have bean initialized.
Main Class SpringBoot
#SpringBootApplication
#EnableAsync
#Controller
public class ...
Example Class Controler
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Component;
#Component
public class ExecutorBase {
private static final Logger log = LoggerFactory.getLogger(ExecutorBase.class);
#Autowired
private TaskExecutor taskExecutor;
#Autowired
private ApplicationContext applicationContext;
private Boolean debug = true;
#PostConstruct
public void atStartup() {
ClasseTaskRunn classeTaskRunn = applicationContext.getBean(ClasseTaskRunn.class);
taskExecutor.execute(classeTaskRunn );
if (debug) {
log.warn("###### Startup ok");
}
}
}
Example Class Task Runnable
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
#Component
#Scope("application")
public class ClasseTaskRunn implements Runnable {
private static final Logger log = LoggerFactory.getLogger(ClasseTaskRunn.class);
#Autowired
ClasseDAO classeDAO;
#Override
public void run() {
longBackgorund();
}
protected void longBackgorund() {
while (test) {
if (debug) {
log.warn("###### DEBUG: " ... );
}
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

Defining spring #EventListener in an abstract super class

I've stared to use spring's #EventListener annotation to create event handlers that handle my non-spring specific events. Initially everything went pretty well. I used a test to verify that I could put the #EventListener annotation on a method of a abstract class and everything worked as expected.
However, once I started adding generics to the mix I started getting NullPointerExceptions from ApplicationListenerMethodAdapter.java:337.
I've created a test case to illustrate the problem. Currently all the test methods fail with the exception:
java.lang.NullPointerException
at java.lang.Class.isAssignableFrom(Native Method)
at org.springframework.context.event.ApplicationListenerMethodAdapter.getResolvableType(ApplicationListenerMethodAdapter.java:337)
at org.springframework.context.event.ApplicationListenerMethodAdapter.resolveArguments(ApplicationListenerMethodAdapter.java:161)
at org.springframework.context.event.ApplicationListenerMethodAdapter.processEvent(ApplicationListenerMethodAdapter.java:142)
at org.springframework.context.event.ApplicationListenerMethodAdapter.onApplicationEvent(ApplicationListenerMethodAdapter.java:106)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:163)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:136)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:381)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:348)
When I move the #EventListener annotation down to each concrete listener the exception disappears and things behave as expected with the exception of testSendingEventWithGenericsWithExtendedUniquePayload.
Questions
Q1) Is it a valid usage pattern to put #EventListener on a method of a abstract super class? I was hoping to implement common behavior there.
Q2) I read about implementing ResolvableTypeProvider on my event in the spring docs. My understanding was that this would allow me to avoid having to create many concrete subclasses for each payload type. This is what I'm attempting to test in testSendingEventWithGenericsWithExtendedUniquePayload. I'm expecting the event fired in this test to be handled by TestEventWithGenericsExtendedUniquePayloadListener but it's not. Have I misunderstood something here?
Spring: 4.2.4.RELEASE
Java: 1.8.0_65
Thanks for your help
Oliver
Test Code
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
import org.springframework.core.ResolvableType;
import org.springframework.core.ResolvableTypeProvider;
import org.springframework.stereotype.Component;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import static org.springframework.core.ResolvableType.*;
/**
* #author Oliver Henlich
*/
#ContextConfiguration
#RunWith(SpringJUnit4ClassRunner.class)
#DirtiesContext
public class EventListenerTest {
private static final Logger log = LoggerFactory.getLogger(EventListenerTest.class);
#Autowired
protected transient ApplicationEventPublisher applicationEventPublisher;
#Test
public void testSendingEvent1() {
log.info("testSendingEvent1");
// this should go to TestEvent1Listener
applicationEventPublisher.publishEvent(new TestEvent1(new UniquePayload()));
}
#Test
public void testSendingEventWithGenerics() {
log.info("testSendingEventWithGenerics");
// this should go to TestEventWithGenericsListener
applicationEventPublisher.publishEvent(new TestEventWithGenerics<>(new UniquePayload()));
}
#Test
public void testSendingEventWithGenericsWithExtendedUniquePayload() {
log.info("testSendingEventWithGenerics");
// I was expecting this to go to TestEventWithGenericsExtendedUniquePayloadListener
applicationEventPublisher.publishEvent(new TestEventWithGenerics<>(new ExtendedUniquePayload()));
}
#Test
public void testSendingEvent2() {
log.info("testSendingEvent2");
// there is no listener for this one
applicationEventPublisher.publishEvent(new TestEvent2(new UniquePayload()));
}
// LISTENERS --------------------------------------------------------------
interface TestDataEventListener<E extends TestDataEvent> {
#SuppressWarnings("unused")
List<String> handleEvent(E event);
}
abstract static class AbstractTestDataEventListener<E extends TestDataEvent> implements TestDataEventListener<E> {
#Override
#EventListener
public final List<String> handleEvent(E event) {
return onEvent(event);
}
public abstract List<String> onEvent(E event);
}
#Component
static final class TestEvent1Listener extends AbstractTestDataEventListener<TestEvent1> {
#Override
public List<String> onEvent(TestEvent1 event) {
log.info("Listener {} handled {}", this, event);
return Collections.emptyList();
}
}
#Component
static final class TestEventWithGenericsListener extends AbstractTestDataEventListener<TestEventWithGenerics> {
#Override
public List<String> onEvent(TestEventWithGenerics event) {
log.info("Listener {} handled {}", this, event);
return Collections.emptyList();
}
}
#Component
static final class TestEventWithGenericsExtendedUniquePayloadListener extends AbstractTestDataEventListener<TestEventWithGenerics<ExtendedUniquePayload>> {
#Override
public List<String> onEvent(TestEventWithGenerics<ExtendedUniquePayload> event) {
log.info("Listener {} handled {}", this, event);
return Collections.emptyList();
}
}
// EVENTS -----------------------------------------------------------------
interface TestDataEvent<T extends Unique> extends ResolvableTypeProvider {
T load();
}
abstract static class AbstractTestDataEvent<T extends Unique> implements TestDataEvent<T> {
protected final UUID uuid;
private final ResolvableType resolvableType;
public AbstractTestDataEvent(T uniqueObject) {
uuid = uniqueObject.getUuid();
ResolvableType temp = ResolvableType.forClass(getClass());
if (temp.hasGenerics()) {
temp = forClassWithGenerics(getClass(), forInstance(uniqueObject));
}
resolvableType = temp;
log.info("class = {} resolvableType = {}", getClass(), resolvableType);
}
#Override
public ResolvableType getResolvableType() {
return resolvableType;
}
}
static final class TestEvent1 extends AbstractTestDataEvent<UniquePayload> {
public TestEvent1(UniquePayload uniqueObject) {
super(uniqueObject);
}
#Override
public UniquePayload load() {
return new UniquePayload(uuid);
}
}
static final class TestEvent2 extends AbstractTestDataEvent<UniquePayload> {
public TestEvent2(UniquePayload uniqueObject) {
super(uniqueObject);
}
#Override
public UniquePayload load() {
return new UniquePayload(uuid);
}
}
static final class TestEventWithGenerics<T extends UniquePayload> extends AbstractTestDataEvent<T> {
public TestEventWithGenerics(T uniqueObject) {
super(uniqueObject);
}
#Override
public T load() {
return (T) new UniquePayload(uuid);
}
}
static class UniquePayload implements Unique {
private final UUID uuid;
public UniquePayload() {
this(UUID.randomUUID());
}
public UniquePayload(UUID uuid) {
this.uuid = uuid;
}
#Override
public UUID getUuid() {
return uuid;
}
}
static class ExtendedUniquePayload extends UniquePayload {
}
interface Unique {
UUID getUuid();
}
#Configuration
#ComponentScan(basePackageClasses = EventListenerTest.class)
public static class ContextConfiguration {
}
}

Categories