In Spring Framework classes that represent an event to be published by the ApplicationEventPublisher and listened to by the #EventListener are
EventObject <- ApplicationEvent <- PayloadApplicationEvent.
My question is what is the non-nullable source in the initial EventObject constructor and all derived subclasses constructors?
Javadocs give a rather vague explanation that it is
"the object upon which the Event in question initially occurred".
Is it an associated domain entity or publisher service or something else?
Additionally, I am confused why is it required at all if #EventListener states that
"Events can be ApplicationEvent instances as well as arbitrary objects"?
I understand source to be the where the event is created. For example, a #Service that processes a web request received from a #Controller. Therefore, when you call ApplicationEventPublisher.publishEvent() the source parameter to the ApplicationEvent event is this, the service.
public class AwesomeEvent extends ApplicationEvent {
private final String howAwesome;
public AwesomeEvent(Object source, String howAwesome) {
super(source);
this.howAwesome = howAwesome;
}
}
#Service
#RequiredArgsConstructor // because, lazy
public class AwesomeService {
private final ApplicationEventPublisher eventPublisher;
public void awesomeMethod() {
// Do superhero awesome stuff
eventPublisher.publishEvent(new AwesomeEvent(this, "Extremely"));
}
}
Just show some code to you. Look at the getApplicationContext() method.
public abstract class ApplicationContextEvent extends ApplicationEvent {
public ApplicationContextEvent(ApplicationContext source) {
super(source);
}
public final ApplicationContext getApplicationContext() {
return (ApplicationContext) getSource();
}
Related
We are working on a multilingual Spring based web application (not Spring Boot).
Now we are searching for the "spring way" of doing the following.
user starts a http session with some parameters, e.g. a locale "de" and/or a country-code "DE" (the type of parameter isn't really important)
user works with application
at some point the user triggers an action that somewhere deep inside needs a "localized" functionality
Example (java pseudocode):
// service with functionality common for all users
#Service
class CommonService implements ICommonService
{
// how to autowire a service based on some info in the actual HttpSession, eg. CustomServiceUK or CustomServiceDE
#Autowired
private ICustomService customServiceImpl;
#Override
public void doSomeAction(String param)
{
... do some common stuff
customResult = customServiceImpl.calculate(param);
... do some common stuff with custom result
}
}
// custom service implementations
#Service("CustomServiceUK")
class CustomServiceUK implements ICustomService
{
#Override
public String calculate(String value)
{
... execute logic on value for an "uk" user
}
}
#Service("CustomServiceDE")
class CustomServiceDE implements ICustomService
{
#Override
public String calculate(String value)
{
... execute logic on value for an "de" user
}
}
How to inject a custom service based on some info in the actual HttpSession (e.g. CustomServiceUK or CustomServiceDE) into CommonService?
What are our options to solve this issue? Is there something like a dynamic #Qualifier or some #Autowired Spring-Factory thing?
(the service implementation to use must not necessarily depend on the locale of the user but on some other piece of session/request information)
Thanks for your answers.
Actually we end up with the following solution which works for us.
We created an additional implementation of ICustomService with name CustomServiceProxy.
This service has #Primary annotation to tell Spring that this component should be injected when no explicit qualifier is supplied.
The service gets the sessionData and a Map with all Spring managed ICustomService-Components injected (Map-Key = Qualifier of the Component).
Now when some method on CustomServiceProxy gets called, it generates the Map-Key based on the actual sessionData (e.g. language), lookup the ICustomService in the Map and delegates the call to this specific service.
// service with functionality common for all users
#Service
class CommonService implements ICommonService
{
// because of #Primary an instance of CustomServiceProxy will be injected
#Autowired
private ICustomService customServiceImpl;
#Override
public void doSomeAction(String param)
{
... do some common stuff
customResult = customServiceImpl.calculate(param);
... do some common stuff with custom result
}
}
// custom service implementations
#Service
#Primary
class CustomServiceProxy implements ICustomService
{
private CustomData sessionData;
private Map<String, ICustomService> services;
#Autowired
public CustomServiceProxy(CustomData sessionData, Map<String, ICustomService> services)
{
this.sessionData = sessionData;
this.services = services;
}
#Override
public String calculate(String value)
{
String serviceName = "CustomService" + sessionData.getLanguage().toUpperCase();
ICustomService customService = services.get(serviceName);
// handle missing service: throw exception or maybe switch to a default implementation
Objects.requireNonNull(customService, "missing CustomService with name " + serviceName);
return customService.calculate(value);
}
}
#Service("CustomServiceUK")
class CustomServiceUK implements ICustomService
{
#Override
public String calculate(String value)
{
... execute logic on value for an "uk" user
}
}
#Service("CustomServiceDE")
class CustomServiceDE implements ICustomService
{
#Override
public String calculate(String value)
{
... execute logic on value for an "de" user
}
}
Has anyone seen a pattern whereby Java constructor parameters are created using a DTO object and then injected into the class using Spring? I believe it is an anti-pattern but am curious if there is a reasonable case where it could be used.
In my mind the ideal thing to do is refactor the code so the need for the single constructor object is redundant.
What's everyones thoughts?
My particular example is of the form:
#Service
public class MyClass {
private MyClassConstructorDto constructorDependencyContainer;
#Autowired
public MyClass(MyClassConstructorDto constructorDependencyContainer) {
this.constructorDependencyContainer = constructorDependencyContainer;
}
public void doSomething() {
constructorDependencyContainer.getCoolDependency().performThing();
}
}
with supporting class
#Component
public class MyClassConstructorDto {
private CoolDependency coolDependency;
public MyClassConstructorDto(CoolDependency coolDependency) {
this.coolDependency = coolDependency;
}
public CoolDependency getCoolDependency() {
return coolDependency;
}
}
I'm trying to create a state machine that uses an enum to specify the states. Since there are a lot of states and the logic implemented by each is pretty complex, I wanted to associate each state with a state handler that will be defined in a different class. Each state handler would implement a common interface (or extend a common abstract class), but each one might have its own set of injected dependencies that the others might not need. So far, something like this....
StateHandler Interface:
public interface StateHandler {
void onActivation();
void onDeactivation();
}
Example StateHandlers:
#Singleton
public class DefaultStateHandler implements StateHandler {
#Inject
public DefaultStateHandler(SomeDependency someDependency) {...}
/** implement onActivation, onDeactivation and state specific logic **/
}
#Singleton
public class OtherStateHandler implements StateHandler {
#Inject
public OtherStateHandler(SomeOtherDependency someOtherDependency) {...}
/** implement onActivation, onDeactivation and state specific logic **/
}
StateManager implementation:
#Singleton
public class StateManager {
private StateType stateType = StateType.DEFAULT;
#Inject
public StateManager() { }
public void changeState(StateType newStateType) {
if (stateType != newStateType) {
stateType.getStateHandler().onDeactivation();
stateType = newStateType;
stateType.getStateHandler().onActivation();
}
}
}
Enum Definition:
public enum StateType {
DEFAULT (/* not sure what to do here */),
OTHER_STATE (...);
private StateHandler stateHandlerInstance;
public getStateHandler { return stateHandlerInstance; }
StateType(/* not sure what to do here */) {
/* assign stateHandlerInstance */
}
}
What I'm trying to figure out is... how do I inject the specific instances of the state handlers when declaring their associated enums? Or if that isn't possible, is there another way of specifying the state handler class for each enum, and then (either in the constructor or by the time its first needed), get the associated state handler instance?
I was originally thinking I needed to inject the state's handler instance into the state enum definition. However, since injection requires public constructors and enums use private constructors, I don't think that approach is feasible.
As mentioned in the comments above, the solution was to use map multibindings.
First the enum StateType is simplified:
public enum StateType {
DEFAULT, OTHER_STATE
}
Now we need a dagger MapKey interface specific to this enum type:
#MapKey
#interface StateTypeKey {
StateType value();
}
Next we need a dagger module which will have provider functions for each StateType / StateHandler combination:
#Module
public StateTypeHandlersModule {
// #Provides #IntoMap // Syntax for dagger >= 2.9
#Provides(type = Provides.Type.MAP) // Syntax for dagger <= 2.8
#StateTypeKey(StateType.DEFAULT)
StateHandler provideDefaultStateHandler(DefaultStateHandler handler) {
return handler;
}
// #Provides #IntoMap // Syntax for dagger >= 2.9
#Provides(type = Provides.Type.MAP) // Syntax for dagger <= 2.8
#StateTypeKey(StateType.OTHER_STATE)
StateHandler provideOtherStateHandler(OtherStateHandler handler) {
return handler;
}
}
Its unfortunately a lot of boilerplate code, which is why I'm using a separate module just for the handlers, and including that in the higher-level state machine module. Note that if you declare two provider functions with the same StateTypeKey, the second handler is ultimately available in the injected map.
Finally, we can inject the Map<StateType, StateHandler> into the StateManager:
#Singleton
public class StateManager {
private Map<StateType, StateHandler> stateHandlerMap;
private StateType stateType = StateType.DEFAULT;
#Inject
public StateManager(Map<StateType, StateHandler> stateHandlerMap) {
this.stateHandlerMap = stateHandlerMap;
}
public void changeState(StateType newStateType) {
if (stateType != newStateType) {
stateHandlerMap.get(stateType).onDeactivation();
stateType = newStateType;
stateHandlerMap.get(stateType).onActivation();
}
}
}
I would like to be able to change the Guice injections at runtime to support multiple injections based on user input. This is what I would like to achieve:
public interface IDao {
public int someMethod();
}
public class DaoEarth implements IDao {
#Override
public int someMethod(){ ... }
}
public class DaoMars implements IDao {
#Override
public int someMethod(){ ... }
}
public class MyClass {
#Inject
private IDao myDao;
public int myMethod(String domain) {
//If Domain == Earth, myDao should be of the type DaoEarth
//If Domain == DaoMars, myDao should be of the type DaoMars
}
}
I was thinking of writing my own Provider, but I don't know how to use that provider to change my bindings at runtime. Any input is welcome and appreciated :)!
Update
Here's what I currently came up with, it's not as pretty as I'd like, so I'm still looking for feedback
public class DomainProvider {
#Inject #Earth
private IDaoProvider earthDaoProvider;
#Inject #Mars
private IDaoProvider marsDaoProvider;
public IDaoProvider get(Domain domain){
switch (domain){
case EARTH:
return earthDaoProvider;
case MARS:
return marsDaoProvider;
}
}
public IDaoProvider get(String domain){
Domain parsedDomain = Domain.valueOf(domain.toUpperCase());
return get(parsedDomain);
}
}
//MarsDaoProvider would be equivalent
public class EarthDaoProvider implements IDaoProvider {
#Inject #Earth
private IDao earthDao;
public IDao getDao() {
return earthDao;
}
}
// This means that in "MyClass", I can do:
public class MyClass {
#Inject
private DomainProvider domainProvider;
public int myMethod(String domain) {
IDaoProvider daoProvider = domainProvider.get(domain);
IDao dao = daoProvider.getDao();
//Now "dao" will be of the correct type based on the domain
}
}
//Of course elsewhere I have the bindings set like
bind(IDao.class).annotatedWith(Earth.class).to(EarthDao.class);
Your version is almost perfect as it is: You're going to need to inject some kind of object that returns one or the other based on code you write, and don't need assisted injection or anything like that. That said, you can skip some of the boilerplate:
public class DomainProvider {
// Just inject Providers directly without binding them explicitly.
#Inject #Earth Provider<IDao> earthDaoProvider;
#Inject #Mars Provider<IDao> marsDaoProvider;
public Provider<IDao> get(Domain domain){
switch (domain){
case EARTH:
return earthDaoProvider;
case MARS:
return marsDaoProvider;
}
}
public Provider<IDao> get(String domain){
Domain parsedDomain = Domain.valueOf(domain.toUpperCase());
return get(parsedDomain);
}
}
Your MyClass in that case would be exactly identical. Here, Provider is either the one-method generic interface com.google.inject.Provider, or the equivalent builtin javax.inject.Provider that it extends. Read more about Guice Providers on the relevant Guice wiki topic.
bind(IDao.class).annotatedWith(Earth.class).to(EarthDao.class);
// You can now inject "#Earth IDao" and also "#Earth Provider<IDao>".
Basically, if you bind a key Foo (to a class, provider, #Provides method, or instance), you automatically get to inject either a Foo or Provider<Foo> with no additional work. Providers are also a great way to ensure that you get a new instance with every call to get, if that's what you want; with your original, you'll always get the same instance of EarthDao or MarsDao for any given DomainProvider you inject. (If you have a scoped binding like #Singleton, Guice will respect that too; Provider just lets Guice get involved, rather than reusing a plain old Java reference.)
This means you can skip your custom EarthDaoProvider and MarsDaoProvider, unless you really need to perform any external initialization on them—at which point you'd probably be better off calling bind(EarthDao.class).toProvider(EarthDaoProvider.class) so the preparation also happens when injecting EarthDao directly. You could also just have DomainProvider return an IDao instance directly by calling get on the appropriate Provider, and be assured that it'll be a new instance every time.
Is it possible to use callbacks with Spring to that they are managed by application context?
My problem is when a service is used from outer by #Autowired, but within that service there is a callback defined using new operator.
The following example executes a method that is worth retrying. Spring offers a RetryCallback for this case (I know this could be acchieved differently, but just to illustrate my callback problem).
#Service
class MyService {
//main method invoked
void run(DataVO dataVO) {
//new operator not usable in spring context
RetryCallback<Object> retryCallback = new RetryCallback<Object>() {
#Override
public Object doWithRetry(RetryContext context) throws Exception {
return createBooking(dataVO);
}
};
}
private Object createBooking(DataVO dataVO) {
//creates the booking, worth retry on specific failures
//uses further injected/autowired services here
}
}
Is it possible to refactor this snippet so that the callback is managed by spring/injected/autowired?
Make your service implement the callback interface :
#Service
class MyService implements RetryCallback<Object> {
//main method invoked
void run(DataVO dataVO) {
}
#Override
public Object doWithRetry(RetryContext context) throws Exception {
return createBooking(dataVO);
}
private Object createBooking(DataVO dataVO) {
//creates the booking, worth retry on specific failures
//uses further injected/autowired services here
}
}