I am trying to do dependency injection in a javaFX project.
I have a
#Singleton
public class WidgetFactory implements IWidgetFactory
My public class ZentaEditorModule extends MvcFxModule contains
#Override
protected void configure() {
super.configure();
//some other code
System.out.println("binding WidgetFactory");
bind(IWidgetFactory.class).to(WidgetFactory.class);
}
In my public class ZentaApplication extends Application I have this, running in application initialization:
final Injector injector = Guice.createInjector(module);
System.out.printf(
"widgetFactory=%s\n", injector.getInstance(IWidgetFactory.class)
);
domainHandler = new DomainHandler(injector, editorModel);
And the DomainHandler starts like this:
public class DomainHandler {
#Inject
private IWidgetFactory widgetFactory;
#Inject
private Injector injector;
public DomainHandler(
final Injector injector, final EditorModelItem editorModelItem
) {
System.out.printf(
"injector in domainHandler=%s\n",
injector
);
System.out.printf(
"injector2 in domainHandler=%s\n",
getInjector(null)
);
System.out.printf(
"widgetFactory in domainHandler=%s\n",
widgetFactory
);
System.out.printf(
"injector parameter=%s\n",
this.injector
);
}
#Inject
public Injector getInjector(final Injector injector) {
return injector;
}
}
And I got this:
binding WidgetFactory
widgetFactory=org.rulez.demokracia.zenta3.editor.widgets.WidgetFactory#39957a81
injector in domainHandler=Injector[bindings=[ProviderInstanceBinding[key=Key[type=com.google.inject.Injector...
injector2 in domainHandler=null
widgetFactory in domainHandler=null
injector parameter=null
DomainHandler constructor
The injector output actually contain this:
LinkedKeyBinding[key=Key[type=org.rulez.demokracia.zenta3.editor.widgets.IWidgetFactory,
annotation=[none]],
source=org.rulez.demokracia.zenta3.editor.ZentaEditorModule.configure(ZentaEditorModule.java:152),
scope=Scopes.NO_SCOPE,
target=Key[type=org.rulez.demokracia.zenta3.editor.widgets.WidgetFactory,
annotation=[none]]],
From that it seems that nothing get injected into my DomainManager instance, at none of the #Inject annotations. Interestingly there are other classes in the code which also have the injector injected, and those are working.
So I guess I do something wrong at the initialization. But what?
Youre not creating your domainhandler through guice and therefore the #inject annotations do nothing. If you want to create this object both ways just use constructor injection and remove the #inject from your fields.
#inject
public DomainHandler(Injector injector, WidgetFactory widgetFactory) {
this.injector = injector;
this.widgetFactory = widgetFactory
}
This way passing them in manually or using getInstance will do the same thing.
#inject on getters doesn't make sense, it can be used on getters but even in the docs is says not normally, and your passing it a null when you print it from your constructor.
Related
After reading some articles about the CDI and Java FX integration, and the source codes of javafx-weaver spring integration.
I decided to add CDI integration to Java FX via the existing javafx-weaver work to simplify the integration work.
The source code can be found here.
I added a simple producer to expose FxWeaver to the CDI context.
#ApplicationScoped
public class FxWeaverProducer {
private static final Logger LOGGER = Logger.getLogger(FxWeaverProducer.class.getName());
#Produces
FxWeaver fxWeaver(CDIControllerFactory callback) {
var fxWeaver = new FxWeaver((Callback<Class<?>, Object>) callback,
() -> LOGGER.log(Level.INFO, "calling FxWeaver shutdown hook")
);
return fxWeaver;
}
public void destroyFxWeaver(#Disposes FxWeaver fxWeaver) {
LOGGER.log(Level.INFO, "destroying FxWeaver bean...");
fxWeaver.shutdown();
}
}
The problem is when using fxWeaver.loadView to load view, the controller did not work as expected.
#ApplicationScoped
#FxmlView("HandlingReport.fxml")
public class HandlingReportController {
private final static Logger LOGGER = Logger.getLogger(HandlingReportController.class.getName());
#Inject
private HandlingReportService handlingReportService;
//fxml properties...
#FXML
private void onSubmit(){...}
}
As above codes, the dependent service handlingReportService in the controller class is null(not injected) when performing an action like onSubmit, it seems when JavaFX handles the #FXML properties binding it always used java reflection API.
If I change the method to public void onSubmit()( use public modifier), all FX fields become null when pressing the onSubmit button.
Any idea to fix this issue?
Marked the controller class as #Dependentscope to resolve the problem.
#Dependent
public class HandlingReportController { ...}
I have problems autowiring beans which are derived from interfaces with annotations.
#Component
#EnableAsync
public interface Calculator {
#Async
public Future<String> calculate();
}
public interface SpecificCalculator extends Calculator {
}
public class ConcreteSpecificCalculator implements SpecificCalculator {
#Override
public Future<String> calculate() {
// do calculation here
return new AsyncResult<String>("hello");
}
}
From what I understood from: Annotations on Interfaces? the #Component Annotation should also apply to all subclasses. Now I have a Mapper class returning all types that are derived from SpecificCalculator.
#Component
public class CalculatorMapper {
#Autowired
private List<SpecificCalculator> specificCalculators;
public List<Calculator> retrieveCalculatorsByModuleId(Integer moduleId) {
if(moduleId==...){
return specificCalculators;
}else{
...
}
}
This is not working. Spring does not find the ConcreteSpecificCalculator and is not injecting it. If I Annotate ConcreteSpecificCalculator with #Component again, it is working. Can anybody explain this to me?
I have a problem with the Automapper on my website and I can't find a solution.
I've created a class called AutoMapperProfile where I'd like to put all my Maps
public class AutoMapperProfile: Profile
{
private readonly IConfiguration _mapper;
public AutoMapperProfile(IConfiguration mapper)
{
_mapper = mapper;
}
protected override void Configure()
{
base.Configure();
_mapper.CreateMap<SlideDTO, Slide>();
_mapper.CreateMap<Slide, SlideDTO>();
}
}
For DI purposes I'm using Ninject, so I've added the following bindings in NinjectWebCommon:
kernel.Bind<IMappingEngine>().ToMethod(ctx => Mapper.Engine);
kernel.Bind<IConfigurationProvider>().ToMethod(x => Mapper.Engine.ConfigurationProvider);
The controller looks like this:
private readonly ISlideRepository slideRepository;
private readonly IMappingEngine mappingEngine;
public HomeController(
ISlideRepository slideRepository,
IMappingEngine mappingEngine)
{
this.slideRepository = slideRepository;
this.mappingEngine = mappingEngine;
}
[HttpGet]
public ActionResult Index()
{
var model = new IndexViewModel();
var slide = slideRepository.GetSlide();
model.Slide = mappingEngine.Map<SlideDTO, Slide>(slide);
return View(model);
}
When I map from SlideDTO to Slide I get the following error:
Missing type map configuration or unsupported mapping.
So my best guess is that I didn't do the binds correctly so that Automapper can see my maps, but I'm not sure how can I fix it.
You don't need to inject IConfiguration into AutoMapperProfile, it already inherits a CreateMap method from Profile.
Make sure that AutoMapperProfile has a parameterless constructor like this:
public class AutoMapperProfile : Profile
{
protected override void Configure()
{
this.CreateMap<SlideDTO, Slide>();
this.CreateMap<Slide, SlideDTO>();
}
}
And then you need to make sure that AutoMapper knows about this profile, here is how you can do it:
Mapper.Engine.ConfigurationProvider.AddProfile<AutoMapperProfile>();
Please note that you can invoke the AddProfile method on any IConfigurationProvider (if you decide not to use the global ConfigurationProvider and Engine).
I need to audit invocations of ejb beans. Saying audit I mean write informations such as current logged user, method name, additional description to a database. I decided to do it by use of CDI decorator:
#Decorator
public class AccountServiceBeanDecorator implements AccountService {
#Inject
#Delegate
#Any
AccountService accountService;
#EJB
private AuditService auditService;
#Override
public Account createAccount(Account account) {
auditService.saveAudit("Method: createAccount", currentUser, "Creating account by admin");
return accountService.createAccount(account);
}
}
and the decorated class:
#Stateless
public class AccountServiceBean implements AccountService {
#Override
public Account createAccount(Account account) {
...
}
}
Now if I call AccountService from another ejb stateless bean, what will happen with transaction?:
#Stateless
public ApplicationFacadeBean implements ApplicationFacade {
#EJB
private AccountService accountService;
#Override
public Account createAccount(Account account) {
return accountService.createAccount(account);
}
}
I wanted to log transaction status in decorator (AccountServiceBeanDecorator) and decorated class (AccountServiceBean), so I injected TransactionSynchronizationRegistry as a resource in both classes:
#Decorator
public class AccountServiceBeanDecorator implements AccountService {
#Inject
#Delegate
#Any
AccountService accountService;
#EJB
private AuditService auditService;
#Resource
private TransactionSynchronizationRegistry reg;
#Override
public Account createAccount(Account account) {
log.info("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
log.info("tx ({}): {}", new Object[] {reg.getTransactionStatus(), reg.getTransactionKey()});
log.info("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
auditService.saveAudit("Method: createAccount", currentUser, "Creating account by admin");
return accountService.createAccount(account);
}
}
and
#Stateless
public class AccountServiceBean implements AccountService {
#Resource
private TransactionSynchronizationRegistry reg;
#Override
public Account createAccount(Account account) {
log.info("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
log.info("tx ({}): {}", new Object[] {reg.getTransactionStatus(), reg.getTransactionKey()});
log.info("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
...
}
}
I received strange behavior:
log from decorator
tx (0): JavaEETransactionImpl: txId=6 nonXAResource=null jtsTx=null localTxStatus=0 syncs=[com.sun.ejb.containers.ContainerSynchronization#68fb15d0]]]
NullPointerException on second log (reg is null).
Can anybody explain it to me? Wheter AccountServiceBean class is called within the same transaction as ApplicationFacade?
Thank you
first: i would not mixing ejbs with cdi interceptors. ejbs has it on interceptor implementations.
second: interceptors are executed in the same transaction as the ejb where the interceptor is around.
possible solution:
create a correct ejb interceptor
put the interceptor around the method / class
create a second ejb (MyLoggerBean) with a method like this logToDatabase(String message) and annotate this method with #TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
inside the interceptor create a class member like this: #EJB private MyLoggerBean loggerBean
inside your #AroundInvoke annotated method you could call loggerBean. logToDatabase(...)
this would create a new transaction from inside the current transaction of the ejb where the interceptor is around
--> i know my english is not very good. but i hope that you understand what i think should work. if i have the time, i make e example on github...
Hmm... what container are you using? Generally I wouldn't suspect a CDI decorator to work on an EJB... I can't think of anything in the JEE spec that I've encountered that would give evidence either way.
Faced with your problem though, I did this with an interceptor, not a decorator. These are supported by the EJB spec... Anyway, here's my code, you would need to grab the variables from the context in your case:
import java.lang.reflect.Method;
import javax.inject.Inject;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
public class InvocationCountInterceptor {
#Inject
private InvocationCounter counter;
#AroundInvoke
public Object intercept(InvocationContext ctx) throws Exception {
Object returnValue = ctx.proceed();
Class<? extends Object> className = ctx.getTarget().getClass();
Method methodName = ctx.getMethod();
counter.incrementCounter(className, methodName);
return returnValue;
}
}
Then whatever EJB or EJB Method you want to audit, I just added this: #Interceptors(InvocationCountInterceptor.class)
Anyone has an example on how to use Freemarker WebappTemplateLoader in FreemarkerConfigurer?
I am using Freemarker with Spring MVC and extending the FreeMarkerConfigurer to add various template loaders and I would also like to add a web app loader to load templates in web app context. But I do not know how to get the servletcontext parameter for its constructor.
public class DesktopFreeMarkerConfigurer extends FreeMarkerConfigurer{
#Override
protected void postProcessConfiguration(Configuration config){
[...]
/* Get templates from the webapp/servlet context */
WebappTemplateLoader watl = new WebappTemplateLoader(<servletContext>, "default/ftl/");
[...]
}
}
I would like to add webapp/default/ftl to template loading path, but as it may be dynamic/configurable, I cannot hardcode it in the xml files.
Any suggestions would be greatly appreciated.
Thank you
Carmen
I assume you are defining DesktopFreeMarkerConfigurer as a spring bean.
In that case, it should be simple to get the servlet context.
Just define this in the DesktopFreeMarkerConfigurer class :
#Autowired private ServletContext context;
Or if you choose, you can also make it implements ServletContextAware :
public class DesktopFreeMarkerConfigurer extends FreeMarkerConfigurer implements ServletContextAware {
private ServletContext servletContext;
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
#Override
protected void postProcessConfiguration(Configuration config){
WebappTemplateLoader watl = new WebappTemplateLoader(this.servletContext, "default/ftl/");
...
}
...
}