CDI and JavaFX (javafx-weaver) Integration - javafx

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 { ...}

Related

Valdiate pojo using #Valid in sping cloud streams

How can one enable validation using #Valid inside the following kafka consumer code ? I am using Spring Cloud Stream (Kafka Stream binder implementation), and there after my implemention is using functional model for example.
#Bean
public Consumer<KStream<String, #Valid Pojo>> process() {
return messages -> messages.foreach((k, v) -> process(v));
}
I tried the following but it didn't work....
#Bean
public DefaultMessageHandlerMethodFactory configureMessageHandlerMethodFactory(
DefaultMessageHandlerMethodFactory messageHandlerMethodFactory,
LocalValidatorFactoryBean validatorFactoryBean) {
messageHandlerMethodFactory.setValidator(validatorFactoryBean);
return messageHandlerMethodFactory;
}
This is simple in spring-kafka by implementing KafkaListenerConfigurer and setting LocalValidatorFactoryBean on KafkaListenerEndpointRegistrar
public class KafkaConfiguration implements KafkaListenerConfigurer {
#Override
public void configureKafkaListeners(KafkaListenerEndpointRegistrar registrar) {
registrar.setValidator(validatorFactoryBean);
}
.....
This is not supported in the functional model at the moment. Even for a non-functional scenario, this is non-trivial for types like KStream. The KafkaListenerConfigurer you mentioned above is for regular Kafka Support with a message channel binder. Your best options for Kafka Streams binder are either using some custom validation in the function itself before continuing with the processing or introducing a schema registry and then perform a schema validation before passing the record to the function.
You can follow the recommendation to create a bean that respects the functional interface of java, that is, it has only a public method, for example:
#Validated
#Component
public class Processor implements Consumer<KStream<String, Pojo>> {
#Override
public void accept(final #Valid #NotNull KStream<String, Pojo> stream) {
stream.foreach((k, v) -> process(v));
}
private void process(final Pojo v) {
}
}
So that generates an execution:
javax.validation.ConstraintDeclarationException: HV000151: A method
overriding another method must not reset the parameter constraint
configuration
It is not possible to overwrite the parameters of the accept method of the consumer functional interface so just remove the interface and leave the component like this:
#Validated
#Component
public class Processor {
public void accept(final #Valid #NotNull KStream<String, Pojo> stream) {
stream.foreach((k, v) -> process(v));
}
private void process(final Pojo v) {
}
}
The problem is that the spring cloud function will not recognize the bean for not extending one of the functional classes.
the workaround I got was:
#RequiredArgsConstructor
public abstract class ValidatedEventListener<T> implements Consumer<T> {
private final Validator validator;
#Override
public void accept(final T t) {
validate(t);
listen(t);
}
public abstract void listen(final T t);
public void validate(final Object event) {
var violations = validator.validate(event);
if (!violations.isEmpty()) throw new ConstraintViolationException(violations);
}
}

Mockito failure: Actually, there were zero interactions with this mock

I'm trying to test a spring rest controller class using JUnit, Mockito, Spring test and Spring Security test. The following is my rest controller class for which i'm performing the test;
#RestController
public class EmployeeRestController {
#Autowired
private EmployeeService employeeService;
#PreAuthorize("hasAnyRole('ROLE_EMPSUPEADM')")
#RequestMapping(value = "/fetch-timezones", method = RequestMethod.GET)
public ResponseEntity<List<ResponseModel>> fetchTimeZones() {
List<ResponseModel> timezones = employeeService.fetchTimeZones();
return new ResponseEntity<>(timezones, HttpStatus.OK);
}
}
The following is my test class;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {SpringConfiguration.class})
#WebAppConfiguration
public class EmployeeRestControllerUnitTest {
private MockMvc mockMvc;
#Autowired
private WebApplicationContext webApplicationContext;
#Mock
private EmployeeService employeeService;
#InjectMocks
private EmployeeRestController employeeRestController;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
Mockito.reset(employeeService);
mockMvc = MockMvcBuilders
.webAppContextSetup(webApplicationContext)
.build();
}
#Test
#WithMockUser(roles = {"EMPSUPEADM"})
public void testFetchTimezones() {
try {
mockMvc.perform(get("/fetch-timezones"))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$", hasSize(4)));
verify(emploeeService, times(1)).fetchTimeZones();
verifyNoMoreInteractions(employeeService);
} catch (Exception e) {
e.printStackTrace();
}
}
}
I made the above test class by refering many tutorials. The problem is i'm not able to understand everything clearly. so, i'm having the following doubts.
I'm creating a mock of EmployeeService and injecting it into EmployeeRestController using #InjectMocks, then why i'm getting the following failure;
Wanted but not invoked:
careGroupService.fetchTimeZones();
-> at com.example.api.test
.restcontroller.EmployeeRestControllerUnitTest
.testFetchTimezones(EmployeeRestControllerUnitTest.java:73)
Actually, there were zero interactions with this mock.
How does MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); works exactly.
I know that MockMvcBuilders.standaloneSetup(employeeRestController) is for testing individual controller classes and spring configuration will not be available for this method. How can we provide spring configuraton for this method, is it possible.
Finally, how does this piece of code: Mockito.reset(employeeService); works.
1) you do verify for
verify(emploeeService, times(1)).fetchTimeZones();
but you didn't setup mock behaviour for it (before you call mockMvc.perform(get("/fetch-timezones"))).
List<ResponseModel> timezones = new ArrayList<>();
when(emploeeService.fetchTimeZones()).thenReturn(timezones );
2) create MockMvc from context. mockmvc emulates web container, use mock for all where is possible but supports http call and gave the possibility to call controller.
It stands up the Dispatcher Servlet and all required MVC components,
allowing us to test an endpoint in a proper web environment, but
without the overhead of running a server.
3) when you use:
#MockBean private EmployeeService employeeService;
you override real service. remove it from test class real service will be used in testing. Instead of use #Mock use #MockBean. #MockBean it's override by container, with #Mock you need to inject this into controller by reflection
or without spring boot with reflection:
#Before
public void init() {
MockitoAnnotations.initMocks(this);
Mockito.reset(employeeService);
mockMvc = MockMvcBuilders
.webAppContextSetup(webApplicationContext)
.build();
EmployeeRestController employeeRestController=
webAppContext.getBean(EmployeeRestController.class);
ReflectionTestUtils.setField(employeeRestController,
"employeeService",
employeeService);
}
4) Mockito.reset(employeeService);- you reset all behaviors that you setupped before. Mock contains information from when(), verify() and controls it , call reset - it's clean all information.

CDI + EJB 3 + EJB Transaction

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)

Isolated Controller Test can't instantiate Pageable

I have a Spring MVC Controller which uses Pagination Support of Spring-Data:
#Controller
public class ModelController {
private static final int DEFAULT_PAGE_SIZE = 50;
#RequestMapping(value = "/models", method = RequestMethod.GET)
public Page<Model> showModels(#PageableDefault(size = DEFAULT_PAGE_SIZE) Pageable pageable, #RequestParam(
required = false) String modelKey) {
//..
return models;
}
}
And I'd like to test the RequestMapping using the nice Spring MVC Test Support. In order to keep these tests fast and isolated from all the other stuff going on, I do not want to create the complete ApplicationContext:
public class ModelControllerWebTest {
private MockMvc mockMvc;
#Before
public void setup() {
ModelController controller = new ModelController();
mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
}
#Test
public void reactsOnGetRequest() throws Exception {
mockMvc.perform(get("/models")).andExpect(status().isOk());
}
}
This approach works fine with other Controllers, that do not expect a Pageable, but with this one I get one of these nice long Spring stacktraces. It complains about not being able to instantiate Pageable:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.springframework.data.domain.Pageable]: Specified class is an interface
at
.... lots more lines
Question: How do I change my test so the magic No-Request-Parameter-To-Pageable conversion happens properly?
Note: In the actual application everything is working fine.
Original answer:
The problem with pageable can be solved by providing a custom argument handler. If this is set you will run in a ViewResolver Exception (loop). To avoid this you have to set a ViewResolver (an anonymous JSON ViewResolver class for example).
mockMvc = MockMvcBuilders.standaloneSetup(controller)
.setCustomArgumentResolvers(new PageableHandlerMethodArgumentResolver())
.setViewResolvers(new ViewResolver() {
#Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
return new MappingJackson2JsonView();
}
})
.build();
Updated (2020):
It is not necessary to add the ViewResolver anymore.
Regarding the parallel answer:
It does not solve the problem for the original question to have this test running without ApplicationContext and/or friends.
Just add #EnableSpringDataWebSupport for test. Thats it.
For spring boot simply adding the ArgumentResolvers solved for me:
From code which triggered the error:
this.mockMvc = MockMvcBuilders.standaloneSetup(weightGoalResource).build();
To this, which works:
this.mockMvc = MockMvcBuilders.standaloneSetup(weightGoalResource)
.setCustomArgumentResolvers(new PageableHandlerMethodArgumentResolver())
.build();

Spring MVC test case

Am new to Spring MVC, i have written web servise using spring MVC and resteasy. My controller is working fine, now need to write testcase but i tried writtig but i never succed am also getting problem in autowiring.
#Controller
#Path("/searchapi")
public class SearchAPIController implements ISearchAPIController {
#Autowired
private ISearchAPIService srchapiservice;
#GET
#Path("/{domain}/{group}/search")
#Produces({"application/xml", "application/json"})
public Collections getSolrData(
#PathParam("domain") final String domain,
#PathParam("group") final String group,
#Context final UriInfo uriinfo) throws Exception {
System.out.println("LANDED IN get****************");
return srchapiservice.getData(domain, group, uriinfo);
}
}
can anyone give me sample code for Test case in spring mvc.
"Spring-MVC" Test case could seem like this using mock objects, for example we want to test my MyControllerToBeTest:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("/spring.xml")
public class MyControllerTest {
private MockHttpServletRequest request;
private MockHttpServletResponse response;
private MyControllerToBeTested controller;
private AnnotationMethodHandlerAdapter adapter;
#Autowired
private ApplicationContext applicationContext;
#Before
public void setUp() {
request = new MockHttpServletRequest();
response = new MockHttpServletResponse();
response.setOutputStreamAccessAllowed(true);
controller = new MyControllerToBeTested();
adapter = new AnnotationMethodHandlerAdapter();
}
#Test
public void findRelatedVideosTest() throws Exception {
request.setRequestURI("/mypath");
request.setMethod("GET");
request.addParameter("myParam", "myValue");
adapter.handle(request, response, controller);
System.out.println(response.getContentAsString());
}
}
but i don't have any experience with REST resource testing, in your case RestEasy.
If you want to test the full service inside the container you can have a look at the REST Assured framework for Java. It makes it very easy to test and validate HTTP/REST-based services.

Resources