Stateless EJB not injected in message driven bean (MDB) - dependency-injection

I have a message driven bean (MDB) that implements MessageListener and has several EJB attributes but non of them are injected so I have to inject them manually. The MDB also has a resource and a CDI bean that are injected fine.
Why the EJBs are not injected automatically? I use NotificationService EJB at other parts of the application and they are injected. Any clue about how to figure out the problem?
I don't get any error from Weblogic 12.1.3, so I can't figure out what's happening here. My code is (full of traces for debugging purposes). I've removed javadocs and method implementations that are not relevant to the problem:
#MessageDriven(name = "MailMessageConsumer", description = "JMS consumer", mappedName = MailJndiConfiguration.JNDI_QUEUE,
activationConfig = {
#ActivationConfigProperty(propertyName = "acknowledgeMode",
propertyValue = "Auto-acknowledge"),
#ActivationConfigProperty(propertyName = "destinationType",
propertyValue = "javax.jms.Queue")
})
#TransactionAttribute(TransactionAttributeType.REQUIRED)
#MessageReceiver(responsibility = "Consumes JMS messages of type MailMessage")
public class MailMessageConsumer implements MessageListener {
private static final Logger log = LoggerFactory.getLogger(MailMessageConsumer.class);
#Resource
private MessageDrivenContext messageDrivenContext;
#EJB
private NotificationService notificationService;
#EJB
private MailClient mailClient;
#Inject
private ApplicationInformation applicationInformation;
#Override
public void onMessage(Message message) {
if (mailClient == null) {
log.error("mailClient object is null");
try {
log.info("Instantiating MailClient manually...");
mailClient = BeanManagerHelper.getReference(MailClient.class);
} catch (Exception e) {
log.error("Cannot instantiate MailClient manually", e);
}
}
if (notificationService == null) {
log.error("notificationService object is null");
try {
log.info("Instantiating NotificationService manually...");
notificationService = BeanManagerHelper.getReference(NotificationService.class);
} catch (Exception e) {
log.error("Cannot instantiate NotificationService manually", e);
}
}
// This never happens
if (applicationInformation == null) {
log.error("applicationInformation object is null");
}
// This never happens
if (messageDrivenContext == null) {
log.error("messageDrivenContext object is null");
}
deliverMessage(message);
}
private void deliverMessage(Message message) {
// Not important
}
private MailMessage retrieveMessage(Message message) {
// Not important
}
private void sendEmail(MailMessage mailMessage) {
// Not important
}
}
MailClient EJB:
#Stateless
#LocalBean
#TransactionAttribute(TransactionAttributeType.MANDATORY)
#Service
public class MailClient {
private static final Logger logger = LoggerFactory.getLogger(MailClient.class);
#Resource(mappedName = MailJndiConfiguration.JNDI_MAIL_SESSION)
private Session mailSession;
#EJB
private NotificationService notificationService;
#Inject
private ApplicationInformation applicationInformation;
enum ValidationError {
NULL_OBJECT("Mail message is null"),
CONTENT_TYPE_EMPTY("Content type not initialized"),
BODY_EMPTY("Message body content is empty");
private static final String ERROR_MESSAGE_PREFIX = "Invalid mail message: ";
private String message = ERROR_MESSAGE_PREFIX;
ValidationError(String message) {
this.message += message;
}
public String getMessage() {
return message;
}
}
public void sendMail(MailMessage mailMessage) throws MailMessageSendingException {
// Not important
}
}
NotificationService EJB:
#Stateless
#LocalBean
#TransactionAttribute(TransactionAttributeType.MANDATORY)
#Service
public class NotificationService {
private static final Logger logger = LoggerFactory.getLogger(NotificationService.class);
#PersistenceContext(unitName = "myEntityManager")
private EntityManager entityManager;
#EJB
private NotificationPendingMessageValidator notificationPendingMessageValidator;
#EJB
private NotificationFinder notificationFinder;
#Inject
private ApplicationInformation applicationInformation;
public NotificationPendingMessageEntity saveNotificationMessageForDeferredMail(NotificationPendingMessageEntity notificationPendingMessageEntity) throws ValidationException {
// Not important
}
public List<NotificationPendingMessageEntity> findNotificationPendingMessageEntities(TimeSlot timeSlot) {
// Not important
}
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public NotificationMailEntity createNewMailEntity() {
// Not important
}
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void updateMailEntity(NotificationMailEntity mailEntity) {
// Not important
}
public void createNotificationMessageProcessedEntity(NotificationProcessedMessageEntity notificationProcessedMessageEntity) {
// Not important
}
public void removeNotificationMessagePendingEntity(NotificationPendingMessageEntity notificationPendingMessageEntity) {
// Not important
}
public void reportMailFailure(NotificationMailEntity mailEntity, String failureNotice) {
// Not important
}
}

Using #Inject for injecting the EJBs instead of #EJB annotation works fine. So there should be a problem with some Weblogic's patches, because testing it in another Weblogic (same version, different patches) it worked as well

Related

keycloak backchannel logout spring session that use redis as session store

I use keycloak as a Central Authentication Service for (single sign on/out) feature.
I have app1, app2, app3. app1 and app2 is monothetic application. app3 use spring session (use redis as session store),
All feature work fine. But I use the back channel to logout for SSO(single sign out) feature, that's works for app1 and app2. But it not work for this app3.
I wonder how to back channel logout application that use spring session
The keycloak admin url invoke when client user send a logout request to it.I find that KeycloakAutoConfiguration#getKeycloakContainerCustomizer() inject WebServerFactoryCustomizer for add KeycloakAuthenticatorValve, and that Valve
use CatalinaUserSessionManagement, but it have not any info about redis as its session store. So I add a customizer for enhence the Valve.
first i set the order of the autoconfig, because extra customizer must be callback after it.
#Slf4j
#Component
public class BeanFactoryOrderWrapper implements DestructionAwareBeanPostProcessor {
#Override
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
}
#Override
public boolean requiresDestruction(Object bean) {
return true;
}
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("getKeycloakContainerCustomizer")) {
Object wrapRes = this.wrapOrder(bean);
return wrapRes;
}
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
private Object wrapOrder(Object bean) {
log.info("rewrite keycloak auto config customizer Order for next custom");
final WebServerFactoryCustomizer origin = (WebServerFactoryCustomizer) bean;
return new KeycloakContainerCustomizerWithOrder(origin);
}
}
class KeycloakContainerCustomizerWithOrder implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, Ordered {
private final WebServerFactoryCustomizer origin;
public KeycloakContainerCustomizerWithOrder(WebServerFactoryCustomizer origin) {
this.origin = origin;
}
#Override
public void customize(ConfigurableServletWebServerFactory factory) {
origin.customize(factory);
}
#Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE - 1;
}
}
I extra RedisIndexedSessionRepository, and set it to proxy object
#Slf4j
#Configuration
#RequiredArgsConstructor
class ContainerConfig {
private final RedisIndexedSessionRepository sessionRepository;
#Bean
public WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> getKeycloakContainerCustomizerGai() {
return configurableServletWebServerFactory -> {
if (configurableServletWebServerFactory instanceof TomcatServletWebServerFactory) {
TomcatServletWebServerFactory container = (TomcatServletWebServerFactory) configurableServletWebServerFactory;
container.getContextValves().stream().filter(ele -> ele.getClass() == KeycloakAuthenticatorValve.class).findFirst().map(ele -> (AbstractKeycloakAuthenticatorValve) ele).ifPresent(valve -> {
try {
final Field field = AbstractKeycloakAuthenticatorValve.class.getDeclaredField("userSessionManagement");
field.setAccessible(true);
final CatalinaUserSessionManagement origin = (CatalinaUserSessionManagement) field.get(valve);
field.set(valve, new CatalinaUserSessionManagementGai(origin, sessionRepository));
} catch (Exception e) {
log.error("enhence valve fail");
}
});
}
};
}
}
#Slf4j
class CatalinaUserSessionManagementGai extends CatalinaUserSessionManagement {
private final CatalinaUserSessionManagement origin;
private final RedisIndexedSessionRepository sessionRepository;
public CatalinaUserSessionManagementGai(CatalinaUserSessionManagement origin, RedisIndexedSessionRepository sessionRepository) {
this.origin = origin;
this.sessionRepository = sessionRepository;
}
public void login(Session session) {
origin.login(session);
}
public void logoutAll(Manager sessionManager) {
origin.logoutAll(sessionManager);
}
public void logoutHttpSessions(Manager sessionManager, List<String> sessionIds) {
for (String sessionId : sessionIds) {
logoutSession(sessionManager, sessionId);
}
}
protected void logoutSession(Manager manager, String httpSessionId) {
try {
final Method method = CatalinaUserSessionManagement.class.getDeclaredMethod("logoutSession", Manager.class, String.class);
method.setAccessible(true);
method.invoke(origin,manager,httpSessionId);
} catch (Exception e) {
log.error("session manager proxy invoke error");
}
// enhence part
sessionRepository.deleteById(httpSessionId);
}
protected void logoutSession(Session session) {
try {
final Method method = CatalinaUserSessionManagement.class.getDeclaredMethod("logoutSession", Session.class);
method.setAccessible(true);
method.invoke(origin,session);
} catch (Exception e) {
log.error("session manager proxy invoke error");
}
}
public void sessionEvent(SessionEvent event) {
origin.sessionEvent(event);
}
}
that work for me

Dagger generated code compilation failed when using #Singleton annotation

I am using Dagger - 2.6 and i have the following classes.
public class Trigger {
public static JSONObject triggerLambda(JSONObject jsonObject) {
DataTransformerComponent daggerDataTransformerComponent = DaggerDataTransformerComponent.create();
return daggerDataTransformerComponent.getHandler().handle(jsonObject);
}
}
Data Handler class:
public class DataHandler {
private static final Logger LOGGER = Logger.getLogger(DataHandler.class.getName());
private A a;
#Inject
public DataHandler(A a) {
this.a = a;
}
public JSONObject handle(JSONObject input) {
LOGGER.info("Json input received - " + input.toString());
return a.executeTransformation(input);
}
}
And a dependency:
public class A {
#Inject
public A() {
}
public JSONObject executeTransformation(JSONObject jsonObject) {
System.out.println("a");
return null;
}
}
My component class looks like:
#Component
public interface DataTransformerComponent {
DataHandler getHandler();
}
When i compile the above code it runs absolutely fine.
Now i want to make my A dependency #Singleton.
So i change my dependency class and component class as follows:
#Singleton
#Component
public interface DataTransformerComponent {
DataHandler getHandler();
}
Dependency class:
#Singleton
public class A {
#Inject
public A() {
}
public JSONObject executeTransformation(JSONObject jsonObject) {
System.out.println("a");
return null;
}
}
But now the generated component shows compilation errors saying:
A_Factory not found and it fails in the initialize() method.
DaggerDataTransformerComponent :
#Generated(
value = "dagger.internal.codegen.ComponentProcessor",
comments = "https://google.github.io/dagger"
)
public final class DaggerDataTransformerComponent implements DataTransformerComponent {
private Provider<A> aProvider;
private Provider<DataHandler> dataHandlerProvider;
private DaggerDataTransformerComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
public static DataTransformerComponent create() {
return builder().build();
}
#SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.aProvider = DoubleCheck.provider(A_Factory.create());
this.dataHandlerProvider = DataHandler_Factory.create(aProvider);
}
#Override
public DataHandler getHandler() {
return dataHandlerProvider.get();
}
public static final class Builder {
private Builder() {}
public DataTransformerComponent build() {
return new DaggerDataTransformerComponent(this);
}
}
}
I am unable to figure out why it does not create _factory class when i use #Singleton annotation.?.
Just use regular JavaScript + node.js, its a lot simpler

Why isn't an custom implemented VaadinServiceInitListener is listening in vaadin 13.0.2?

I would like to validate user is signed in or not to achieve it i found something called VaadinServiceInitListener in vaadin 13.0.2 This class is used to listen to BeforeEnter event of all UIs in order to check whether a user is signed in or not before allowing entering any page.
I have created an vaadin 13.0.2 project with app-layout-addon by appreciated implemented login functionality and VaadinServiceInitListener to check whether a user is signed in or not.
public class AAACATInitListener implements VaadinServiceInitListener {
private static final long serialVersionUID = 1L;
private static InAppSessionContextImpl appContextImpl;
#Override
public void serviceInit(ServiceInitEvent event) {
System.out.println("in service init event");
event.getSource().addUIInitListener(new UIInitListener() {
private static final long serialVersionUID = 1L;
#Override
public void uiInit(UIInitEvent event) {
event.getUI().addBeforeEnterListener(new BeforeEnterListener() {
private static final long serialVersionUID = 1L;
#Override
public void beforeEnter(BeforeEnterEvent event) {
appContextImpl = (InAppSessionContextImpl)VaadinSession.getCurrent().getAttribute("context");
if (appContextImpl == null) {
WebBrowser webBrowser = UI.getCurrent().getSession().getBrowser();
String address = webBrowser.getAddress();
if(RememberAuthService.isAuthenticated(address) != null && !RememberAuthService.isAuthenticated(address).isEmpty()) {
//System.out.println("Found Remembered User....");
IBLSessionContext iblSessionContext = null;
try {
iblSessionContext = new UserBLManager().doRememberedStaffUserLogin(RememberAuthService.isAuthenticated(address), "");
if(iblSessionContext != null) {
InAppSessionContextImpl localAppContextImpl = new InAppSessionContextImpl();
localAppContextImpl.setBLSessionContext(iblSessionContext);
localAppContextImpl.setModuleGroupList(iblSessionContext.getSessionAccessControl().getPermittedModuleGroups());
appContextImpl = localAppContextImpl;
event.rerouteTo(ApplicationMainView.class);
}else {
Notification.show("Your access has been expired, Please contact your administrator", 5000, Position.BOTTOM_CENTER);
}
} catch (AuthenticationFailedException e) {
Notification.show("Authentication Failed, Please Reset Cookies And Try Again", 5000, Position.BOTTOM_CENTER);
} catch (Exception e){
e.printStackTrace();
Notification.show("Unexpected Error Occurred, Please Reset Cookies And Try Again", 5000, Position.BOTTOM_CENTER);
}
}else {
System.out.println("Session context is null, creating new context");
appContextImpl = new InAppSessionContextImpl();
VaadinSession.getCurrent().setAttribute("context", appContextImpl);
event.rerouteTo(LoginView.class);
}
} else {
System.out.println("Session context is not null");
InAppSessionContextImpl localAppContextImpl = new InAppSessionContextImpl();
localAppContextImpl.setBLSessionContext(appContextImpl.getBLSessionContext());
localAppContextImpl.setModuleGroupList(appContextImpl.getModuleGroupList());
appContextImpl = localAppContextImpl;
event.rerouteTo(ApplicationMainView.class);
}
}
});
}
});
}
public static void setBLSessionContext(IBLSessionContext iblSessionContext) {
appContextImpl.setBLSessionContext(iblSessionContext);
}
public static void setModuleGroupList(List<ModuleGroupVO> moduleGroupList) {
appContextImpl.setModuleGroupList(moduleGroupList);
}
private class InAppSessionContextImpl implements InAppSessionContext {
private static final long serialVersionUID = 1L;
private List<ModuleGroupVO> moduleGroupList;
private IBLSessionContext iblSessionContext;
private Map<String, Object> attributeMap;
public InAppSessionContextImpl() {
this.attributeMap = new HashMap<String, Object>();
}
#Override
public List<ModuleGroupVO> getModuleGroupList() {
return moduleGroupList;
}
public void setModuleGroupList(List<ModuleGroupVO> moduleGroupList) {
this.moduleGroupList = moduleGroupList;
}
#Override
public IBLSessionContext getBLSessionContext() {
return iblSessionContext;
}
public void setBLSessionContext(IBLSessionContext iblSessionContext) {
this.iblSessionContext = iblSessionContext;
}
#Override
public IBLSession getBLSession() {
if(iblSessionContext != null)
return iblSessionContext.getBLSession();
return null;
}
#Override
public boolean isPermittedAction(String actionAlias) {
if (getBLSessionContext() != null) {
if (getBLSessionContext().getSessionAccessControl() != null) {
return getBLSessionContext().getSessionAccessControl().isPermittedAction(actionAlias);
}
}
return false;
}
#Override
public void setAttribute(String key, Object attribute) {
attributeMap.put(key, attribute);
}
#Override
public Object getAttribute(String key) {
return attributeMap.get(key);
}
}
}
Expected results redirect to login page if user not signed in or else to main application page but AAACATInitListener is not listening.
If you are using Spring, simply add a #Component annotation to the class and it should work. If youre not using Spring, follow #codinghaus' answer.
To make Vaadin recognize the VaadinServiceInitListener you have to create a file called com.vaadin.flow.server.VaadinServiceInitListener and put it under src/main/resources/META-INF/services. Its content should be the full path to the class that implements the VaadinServiceInitListener interface. Did you do that?
You can also find a description on that in the tutorial.
The correct pattern to use beforeEnter(..) is not do it via VaadinServiceInitListener , instead you should implement BeforeEnterObserver interface in the view where you need use it and override beforeEnter(..) method with your implementation.
public class MainView extends VerticalLayout implements RouterLayout, BeforeEnterObserver {
...
#Override
public void beforeEnter(BeforeEnterEvent event) {
...
}
}

Default to content_type application/json with overriden isFatal from DefaultExceptionStrategy

I'd like to not require my clients to provide content_type application/json but just default to it. I got this working.
I also tried to combine with another example to implement a custom isFatal(Throwable t) from ConditionalRejectingErrorHandler. I can get my custom error handler to fire, but then it seems to require the content_type property again. I can't figure out how to get them both to work at the same time.
Any ideas?
The below successfully works to not require content_type
EDIT: The below code does not work as I thought. An old message in the queue with the property content_type application/json must have been pulled in
#EnableRabbit
#Configuration
public class ExampleRabbitConfigurer implements
RabbitListenerConfigurer {
#Value("${spring.rabbitmq.host:'localhost'}")
private String host;
#Value("${spring.rabbitmq.port:5672}")
private int port;
#Value("${spring.rabbitmq.username}")
private String username;
#Value("${spring.rabbitmq.password}")
private String password;
#Autowired
private MappingJackson2MessageConverter mappingJackson2MessageConverter;
#Autowired
private DefaultMessageHandlerMethodFactory messageHandlerMethodFactory;
#Bean
public MappingJackson2MessageConverter mappingJackson2MessageConverter() {
return new MappingJackson2MessageConverter();
}
#Bean
public DefaultMessageHandlerMethodFactory messageHandlerMethodFactory() {
DefaultMessageHandlerMethodFactory factory = new DefaultMessageHandlerMethodFactory();
factory.setMessageConverter(mappingJackson2MessageConverter);
return factory;
}
#Override
public void configureRabbitListeners(final RabbitListenerEndpointRegistrar registrar) {
registrar.setMessageHandlerMethodFactory(messageHandlerMethodFactory);
}
The below here works to override isFatal() in ConditionalRejectingErrorHandler. The SimpleRabbitListenerContainerFactory.setMessageConverter() seems like it should serve the same purpose as DefaultMessageHandlerMethodFactory.setMessageConverter(). Obviously this is not the case.
#EnableRabbit
#Configuration
public class ExampleRabbitConfigurer {
#Value("${spring.rabbitmq.host:'localhost'}")
private String host;
#Value("${spring.rabbitmq.port:5672}")
private int port;
#Value("${spring.rabbitmq.username}")
private String username;
#Value("${spring.rabbitmq.password}")
private String password;
#Autowired
ConnectionFactory connectionFactory;
#Autowired
Jackson2JsonMessageConverter jackson2JsonConverter;
#Autowired
ErrorHandler amqpErrorHandlingExceptionStrategy;
#Bean
public Jackson2JsonMessageConverter jackson2JsonConverter() {
return new Jackson2JsonMessageConverter();
}
#Bean
public ErrorHandler amqpErrorHandlingExceptionStrategy() {
return new ConditionalRejectingErrorHandler(new AmqpErrorHandlingExceptionStrategy());
}
#Bean
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setMessageConverter(jackson2JsonConverter);
factory.setErrorHandler(amqpErrorHandlingExceptionStrategy);
return factory;
}
public static class AmqpErrorHandlingExceptionStrategy extends ConditionalRejectingErrorHandler.DefaultExceptionStrategy {
private final Logger LOGGER = org.slf4j.LoggerFactory.getLogger(getClass());
#Override
public boolean isFatal(Throwable t) {
if (t instanceof ListenerExecutionFailedException) {
ListenerExecutionFailedException lefe = (ListenerExecutionFailedException) t;
LOGGER.error("Failed to process inbound message from queue "
+ lefe.getFailedMessage().getMessageProperties().getConsumerQueue()
+ "; failed message: " + lefe.getFailedMessage(), t);
}
return super.isFatal(t);
}
}
Use an "after receive" MessagePostProcessor to add the contentType header to the inbound message.
Starting with version 2.0, you can add the MPP to the container factory.
For earlier versions you can reconfigure...
#SpringBootApplication
public class So47424449Application {
public static void main(String[] args) {
SpringApplication.run(So47424449Application.class, args);
}
#Bean
public ApplicationRunner runner(RabbitListenerEndpointRegistry registry, RabbitTemplate template) {
return args -> {
SimpleMessageListenerContainer container =
(SimpleMessageListenerContainer) registry.getListenerContainer("myListener");
container.setAfterReceivePostProcessors(m -> {
m.getMessageProperties().setContentType("application/json");
return m;
});
container.start();
// send a message with no content type
template.setMessageConverter(new SimpleMessageConverter());
template.convertAndSend("foo", "{\"bar\":\"baz\"}", m -> {
m.getMessageProperties().setContentType(null);
return m;
});
template.convertAndSend("foo", "{\"bar\":\"qux\"}", m -> {
m.getMessageProperties().setContentType(null);
return m;
});
};
}
#Bean
public Jackson2JsonMessageConverter converter() {
return new Jackson2JsonMessageConverter();
}
#RabbitListener(id = "myListener", queues = "foo", autoStartup = "false")
public void listen(Foo foo) {
System.out.println(foo);
if (foo.bar.equals("qux")) {
throw new MessageConversionException("test");
}
}
public static class Foo {
public String bar;
public String getBar() {
return this.bar;
}
public void setBar(String bar) {
this.bar = bar;
}
#Override
public String toString() {
return "Foo [bar=" + this.bar + "]";
}
}
}
As you can see, since it modifies the source message, the modified header is available in the error handler...
2017-11-22 09:39:26.615 WARN 97368 --- [cTaskExecutor-1] ingErrorHandler$DefaultExceptionStrategy : Fatal message conversion error; message rejected; it will be dropped or routed to a dead letter exchange, if so configured: (Body:'{"bar":"qux"}' MessageProperties [headers={}, contentType=application/json, contentEncoding=UTF-8, contentLength=0, receivedDeliveryMode=PERSISTENT, priority=0, redelivered=false, receivedExchange=, receivedRoutingKey=foo, deliveryTag=2, consumerTag=amq.ctag-re1kcxKV14L_nl186stM0w, consumerQueue=foo]), contentType=application/json, contentEncoding=UTF-8, contentLength=0, receivedDeliveryMode=PERSISTENT, priority=0, redelivered=false, receivedExchange=, receivedRoutingKey=foo, deliveryTag=2, consumerTag=amq.ctag-re1kcxKV14L_nl186stM0w, consumerQueue=foo])

Jersy2 inject slf4j Logger

I'm trying to understand Jersey 2 development and context-dependency injection.
I don't understand how to inject into a resource an object that needs initialization parameters in the constructor.
For example: I'd like to #Inject slf4j Logger, built using LoggerFactory.
My resource class is:
#Path("/myresource")
public class MyResource {
#Inject
private Logger log;
#GET
#Produces(MediaType.APPLICATION_JSON)
public Answer status() {
log.info("STATUS");
return new Answer(200, "Server up and running # "+ ZonedDateTime.now());
}
}
My Resource config is:
public class MyAppextends ResourceConfig {
public MyApp() {
register(new MyBinder());
packages(true, "my.packages");
}
}
public class MyBinder extends AbstractBinder {
#Override
protected void configure() {
bindFactory(MyLoggerFactory.class).to(org.slf4j.Logger.class);
}
}
Finally, the Factory is:
public class MyLoggerFactory implements Factory<Logger> {
#Override
public Logger provide() {
return LoggerFactory.getLogger(TYPE_FOR_LOGGING.class);
}
#Override
public void dispose(Logger logger) {
}
}
How can I specify TYPE_FOR_LOGGING as argument, in order to Inject the correctly initialized Logger in every resource I want?
Thanks
What you are looking for is called the InstantiationService. You can inject it into Factories to find out who is calling the factory inside of the provide method.
Below find a code sample from the hk2 tests that illustrate the use of the InstantiationService.
#Singleton
public class CorrelationFactory implements Factory<PerLookupServiceWithName> {
private final static PerLookupServiceWithName NULL_SERVICE = new PerLookupServiceWithName() {
#Override
public String getName() {
return null;
}
};
#Inject
private InstantiationService instantiationService;
/* (non-Javadoc)
* #see org.glassfish.hk2.api.Factory#provide()
*/
#Override #PerLookup
public PerLookupServiceWithName provide() {
InstantiationData data = instantiationService.getInstantiationData();
if (data == null) {
return NULL_SERVICE;
}
Injectee parent = data.getParentInjectee();
if (parent == null) {
return NULL_SERVICE;
}
Class<?> parentClass = parent.getInjecteeClass();
if (parentClass == null) {
return NULL_SERVICE;
}
Correlator correlator = parentClass.getAnnotation(Correlator.class);
if (correlator == null) {
return NULL_SERVICE;
}
final String fName = correlator.value();
return new PerLookupServiceWithName() {
#Override
public String getName() {
return fName;
}
};
}
/* (non-Javadoc)
* #see org.glassfish.hk2.api.Factory#dispose(java.lang.Object)
*/
#Override
public void dispose(PerLookupServiceWithName instance) {
// DO nothing
}
}

Resources