Within my web application I have a tool for generating PDF/XLS reports. These "reporters" inherit from a basic controller and they just describe the reporting functionality, something like:
public abstract class Reporter {
getPath() {
return "/reporter/" + getClass().getSimpleName().replace("Reporter", "").toLowerCase() + ".{pdf|xls}";
}
handleRequest() {
// prepare the data
generateReport(...)
// do something with it
// then report pdf or excel
}
}
#Controller
public class DailyReporter extends Reporter {
#Override
void generateReport(...) {}
}
#Controller
public class AverageReporter extends Reporter {
#Override
void generateReport(...) {}
}
In this way I can just describe the data for each Reporter.
Using Spring MVC, the getPath() method is actually part of the Annotation, but using getClass().getSimpleName().toLowerCase() in the annotation is not possible as it needs to be "Compile time constant". Is there a way to do this with Spring MVC?
Don't use inheritance. Use composition/delegation.
Have a single controller, mapped to /reporter/{type}.{pdf|xls}. Define an interface Reporter, and one spring bean implementing that interface per type of report. Inject a List<Reporter> in your controller. And for each request, find the reporter responsible for the type passed in the URL, and call it.
Related
I have a Spring Boot application where I would like to ensure that a list of decorators are verified to be executed. These decorators all extend from the same Abstract class, which in turn extend from the same interface, and they are autowired into a service class as a list of decorators. I would have thought that providing the #SpyBean(MyDecorator.class) at the class level of the test would have done the trick, but I got the error specifying that the decorator is not a spy. It looks like the MockitoPostProcessor class expects that we provide the individual concrete classes in the annotation as so #SpyBean(classes = {decorator1.class,decorator2.class}). I tried the latter, and it worked.
However, the issue that I have with this is that we have to add to this list every time we create a new decorator, which is not ideal. This is why I thought it makes sense to have the interface type be checked as well. Please let me know if there is a better way of doing this, or if I missed something. A thought that crossed my mind was to define my own post processor to wrap any bean from a defined type in a mockito spy, but I would like to check here first. Here is a skeleton definition of the classes to help you understand my dilemma.
MyDecorator.java
public interface MyDecorator{
public void decorate(SomeObject obj);
}
AbstractDecorator.java
public class AbstractDecorator implements MyDecorator{
//common decorator logic
}
Decorator1.java
#Component
public class Decorator1 extends AbstractDecorator{
public void decorate(SomeObject obj){
//decoration logic
}
}
Decorator2.java
#Component
public class Decorator2 extends AbstractDecorator{
public void decorate(SomeObject obj){
//decoration logic
}
}
DecorationService.java
#Service
public class DecorationService implements Service{
#Autowired
private List<MyDecorator> decoratorList;
public void processDecorators(){
//go through list of decorators and process some object
}
}
DecoratorServiceTest.java
#Runwith(SpringRunner.class)
#SpringBootTest
#ActiveProfiles("test")
//#SpyBean(MyDecorator.class) //<-- This doesn't wrap the classes in a spy and errors out
#SpyBean(classes = {Decorator1.class, Decorator2.class}) //<-- This works
public class DecoratorServiceTest{
#Autowired
private List<MyDecorator> decoratorList;
#Test
public void testProcessDecorator(){
//verify that each decorator was processed
}
}
I posted a spring boot github issue here. Hopefully we would either see an improvement on it or we get an explanation as to why it is designed in this way.
I have a workaround in place that I'm using which is I've created a class that implements Spring's BeanPostProcessor interface, and I override the postProcessAfterInitialization method, and I check if the class is what I'm expecting, then I would wrap it in a mockito spy. Also, you would need to define the spring bean.
Here is a snippet of the class that I created.
public class SpyBeanPostProcessor<T> implements BeanPostProcessor{
/**
* The class type to spy on.
*/
private Class<T> typeToSpy;
/**
* Construct a SpyBeanPostProcessor with a class type to wrap
* as a {#link org.mockito.Spy}
* #param typeToSpy The class type to spy on.
*/
public SpyBeanPostProcessor(Class<T> typeToSpy) {
this.typeToSpy = typeToSpy;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (typeToSpy.isAssignableFrom(bean.getClass())){
return Mockito.spy(bean);
}else{
return bean;
}
}
}
I also needed to create a new spring bean that loads the BeanPostProcessor as shown below.
#Bean
public static SpyBeanPostProcessor decoratorSpyBeanPostProcessor(){
return new SpyBeanPostProcessor(MyDecorator.class);
}
New to spring magic, hoping spring magic can solve my dilemma.
My groovy/spring app uses a jar to handle logging in. I want to override a method in the jar to do some custom processing during the log in process (post login).
The class in the jar looks like this:
#Component
class Processor extends GenericProcessor {
#Override
ProcessedRequest handle(Request request) {
// do things
return processRequest(request)
}
//Do nothing method method I want to override
ProcessedRequest processRequest(request) {
return request
}
}
In my application, I have subclass that extends the jar class:
class MyProcessor extends Processor {
#Override
ProcessedRequest processRequest(request) {
//do custom processing
return request
}
}
I tried making MyProcessor an #Component, but the Processor class just calls its own processRequest method instead of the processRequest method in myProcessor.
Is there something I can do with Spring to say "Whenever myProcessor exists, use it instead of Processor" through some combination of #Component/#Bean/#Qualifier?
Other notes:
Processor in the jar is called within the jar, so it isn't easy to replace the call location with myProcessor
I do have access to change the jar source code, though I would rather not, as its a shared jar.
as a suggestion, try to put #Primary under your class MyProcessor. use #Primary to give higher preference to a bean when there are multiple beans of the same type
#Component
#Primary
class myProcessor extends Processor {
...
}
I have tried to find documentation on how to manually configure a RestController (i.e in a Configuation class). That means without using the RestController annotation. Considering all the other annotations, like mapping, pathvariables etc. is at all possible?
A controller is essentially a component with a request mapping. See RequestMappingHandlerMapping.
#Override
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
If you want to instantiate a "rest controller" through configuration, you can probably do so via the following:
#Configuration
public class MyConfiguration {
#Bean
public MyController() {
return new MyController();
}
}
#ResponseBody
public class MyController {
#RequestMapping("/test")
public String someEndpoint() {
return "some payload";
}
}
But I don't think you'll be able to configure the request mappings (path variables, etc) in the configuration though; at least I haven't seen an example nor figured out how.
I'm testing a web application using JUnit. The buisness layer of this application is writed in EJB stateless classes.
So I do "in container" tests with JUnit and Glassfish-embedded.
All works fine so far, EJBs are injected using lookup functions.
Here are a simple test case :
public class SupportTest {
private static EJBContainer container;
private static MyEJB myEjb;
#BeforeClass
public static void setUpServices() throws NamingException {
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(EJBContainer.MODULES, new File("target/classes"));
container = EJBContainer.createEJBContainer(properties);
myEjb = (MyEJB) container.getContext().lookup("java:global/classes/MyEJB");
}
#Test
public void test() {
myEjb.doSomething("user_login");
}
}
Now I have a SessionScoped POJO (CDI) which keep information such as user login and so on.
This Pojo is injected inside a static class. Like this :
public class MyStaticClass {
public static boolean verifyLogin(String login) {
MySessionPojo mySessionPojo = CDI.current().select(MySessionPojo.class).get();
return mySessionPojo.getLogin().equals(login);
}
}
This static class is used in EJB to secure the buisness code, like this :
#Stateless
public class MyEJB {
public void doSomething(String login) {
if(MyStaticClass.verifyLogin(login)){
//do something
}
}
}
Inside a normal Glassfish 4.1 server, the injection of the POJO inside the static class works fine.
Inside the Glassfish-embedded, the POJO injection fails with this message :
WELD-001303: No active contexts for scope type javax.enterprise.context.SessionScoped
I assume this is because there is no Http Session bound to it.
Is there a way to simulate/create à SessionContext programmatically?
Thanks.
Ok, I finally find a workaround. I use the framework JMockit to replace the static class by a mock class, with fake methods which always return TRUE. (I had already tested Mockito and PowerMock, but both didn't work).
I have a project where I have an interface, an Abstract class implementing the same interface and then a set of concrete classes which implement this interface and extend the Abstract Class.
public interface Invoice
{
void process();
}
#component
public abstract class AbstractInvoice(){
#Resource
protected Writer writer;
protected validateInvoice(){
//some implementation
}
}
#Component
public Class TypeAInvoice() extends AbstractInvoice implements Invoice{
#Override
public void process(){
//... some code
writer.write();
}
}
public Interface Writer(){
public void write();
}
#Component
public class CDWriter implements Writer{
#Override
public void write() { /* implementation.....*/}
}
Spring file has a component scan for the package.
<context:annotation-config>
<context:component-scan base-package="com.xyz" />
I am using a factory to get an instance of TypeAInvoice invoice
Now calling invoice.process() gets a NPE when getting to write.write()
I am not sure what am I missing here. I tried to see the component scan and scope and could not find anything conceptually wrong.
I am using a factory to get an instance of TypeAInvoice invoice
Depending on what your Factory does, this may be the problem. If the Factory creates a new TypeAInvoice, Spring wiring doesn't apply. You have to query the Spring context for the Bean. One way (though not very pretty) is to use ContextLoader:
return ContextLoader.getCurrentWebApplicationContext().getBean(TypeAInvoice.class)
I'd say static Factories and Spring don't go to well together. Spring stands for the Inversion of Control pattern, while Factories stand for the Service Locator pattern. I'd suggest that you get rid of your factories and autowire your Spring Beans.
Everything is good, except for the fact you use a factory to get the TypeAInvoice. If you create it like TypeAInvoice typer = new TypeAInvoice() then spring knows nothing of it, the Writer is not autowired, there for you get the NullPointerException. You should get the bean from the spring application context.
In my case, inside a Spring4 Application, i had to use a classic Abstract Factory Pattern(for which i took the idea from - http://java-design-patterns.com/patterns/abstract-factory/) to create instances each and every time there was a operation to be done.So my code was to be designed like:
public abstract class EO {
#Autowired
protected SmsNotificationService smsNotificationService;
#Autowired
protected SendEmailService sendEmailService;
...
protected abstract void executeOperation(GenericMessage gMessage);
}
public final class OperationsExecutor {
public enum OperationsType {
ENROLL, CAMPAIGN
}
private OperationsExecutor() {
}
public static Object delegateOperation(OperationsType type, Object obj)
{
switch(type) {
case ENROLL:
if (obj == null) {
return new EnrollOperation();
}
return EnrollOperation.validateRequestParams(obj);
case CAMPAIGN:
if (obj == null) {
return new CampaignOperation();
}
return CampaignOperation.validateRequestParams(obj);
default:
throw new IllegalArgumentException("OperationsType not supported.");
}
}
}
#Configurable(dependencyCheck = true)
public class CampaignOperation extends EO {
#Override
public void executeOperation(GenericMessage genericMessage) {
LOGGER.info("This is CAMPAIGN Operation: " + genericMessage);
}
}
Initially to inject the dependencies in the abstract class I tried all stereotype annotations like #Component, #Service etc but even though Spring context file had ComponentScanning for the entire package, but somehow while creating instances of Subclasses like CampaignOperation, the Super Abstract class EO was having null for its properties as spring was unable to recognize and inject its dependencies.After much trial and error I used this **#Configurable(dependencyCheck = true)** annotation and finally Spring was able to inject the dependencies and I was able to use the properties in the subclass without cluttering them with too many properties.
<context:annotation-config />
<context:component-scan base-package="com.xyz" />
I also tried these other references to find a solution:
http://www.captaindebug.com/2011/06/implementing-springs-factorybean.html#.WqF5pJPwaAN
http://forum.spring.io/forum/spring-projects/container/46815-problem-with-autowired-in-abstract-class
https://github.com/cavallefano/Abstract-Factory-Pattern-Spring-Annotation
http://www.jcombat.com/spring/factory-implementation-using-servicelocatorfactorybean-in-spring
https://www.madbit.org/blog/programming/1074/1074/#sthash.XEJXdIR5.dpbs
Using abstract factory with Spring framework
Spring and Abstract class - injecting properties in abstract classes
Inject spring dependency in abstract super class
Spring autowire dependency defined in an abstract class
Spring can you autowire inside an abstract class?
Please try using **#Configurable(dependencyCheck = true)** and update this post, I might try helping you if you face any problems.
So precisely my point here is you don't need to get a bean from spring context all the time.