Force #Autowired spring boot and webFlux - java

My application use spring boot and webflux with tomcat embedded.
I use a 3rd library that contains some servlet listeners.
A listener property injector of BagServletContextListener returns null when the app is started.
#WebListener
public class BagServletContextListener implements ServletContextListener {
#Autowired
private BagInjector injector;
#Override
public void contextInitialized(ServletContextEvent event) {
this.injector.inject();
}
}
How can I force initialization of this component through #bean or other way?
a piece of my pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
Note: The packaging of app is a war.
The lack of initialization of this component cause null pointer exception in contextInitialized method.
[ERROR ] SRVE0283E: Exception caught while initializing context: java.lang.NullPointerException at com.devIo.ee.BagServletContextListener.contextInitialized(BagServletContextListener.java:33) at com.ibm.ws.webcontainer.webapp.WebApp.notifyServletContextCreated(WebApp.java:2391) at [internal classes]

You have not told Spring Boot to scan your BagServletContextListener class. The #WebListener does not accomplish that.
Add #ServletComponentScan to your SpringBootApplication class to ensure the BagInjector is scanned - and Spring knows how to autowire it for you.
Like this:
#ServletComponentScan
#SpringBootApplication
public class SpringBootApp {
public static void main(String[] args) {
SpringApplication.run(SpringBootApp.class, args);
}
}

Related

Rest controller test with #WebMvcTest, Could not instantiate JAXBContext for PagedResources

I have some tests that were failing with Error creating bean with name 'entityManagerFactory' this answer solved it for me https://stackoverflow.com/a/47504698/6945345 but broke my Controller test with Could not instantiate JAXBContext for class [class org.springframework.hateoas.PagedResources]: Implementation of JAXB-API has not been found on module path or classpath. This is because I think #WebMvcTest does not pick up the JAXB-API. What should I do to resolve this the best way?
The controller test class that is given the exception:
#RunWith(SpringRunner.class)
#WebMvcTest(BiodiversityController.class)
#Import(SpecieResourceAssembler.class)
public class BiodiversityControllerTest {
#MockBean
private SpecieService specieService;
#Autowired
private MockMvc mockMvc;
#Autowired
private SpecieResourceAssembler specieResourceAssembler;
#Before
public void setup() {
mockMvc = MockMvcBuilders.standaloneSetup(new BiodiversityController(specieService, specieResourceAssembler))
.setCustomArgumentResolvers(new PageableHandlerMethodArgumentResolver())
.build();
}
#Test
public void getAllSpecies_ShouldReturnSpecies() throws Exception {
PageRequest pageRequest = PageRequest.of(0, 20);
given(specieService.getAllSpecies(pageRequest)).willReturn(new PageImpl<>(
Collections.singletonList(createAnimaliaOrestias()), pageRequest, 1));
mockMvc.perform(MockMvcRequestBuilders.get("/species?page=0&size=20"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.content", hasSize(1)))
.andExpect(jsonPath("$.content.[0].name").value(NAME_ORESTIAS));
verify(specieService).getAllSpecies(pageRequest);
}
}
My pom dependencies with the jaxb-api
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
</dependencies>
If you use Java 9 or higher you need to add the following VM options to start tests/application
--add-modules
java.xml.bind

Prometheus metrics - not found

I have spring boot application and i am using vertx.
I want to monitor the services and the jvm and for that i chose Prometheus.
This is my MonitoringConfig class:
#Configuration
public class MonitoringConfig {
#Bean
SpringBootMetricsCollector springBootMetricsCollector(Collection<PublicMetrics> publicMetrics) {
SpringBootMetricsCollector springBootMetricsCollector = new SpringBootMetricsCollector(publicMetrics);
springBootMetricsCollector.register();
return springBootMetricsCollector;
}
#Bean
public ServletRegistrationBean servletRegistrationBean() {
DefaultExports.initialize();
return new ServletRegistrationBean(new MetricsServlet(), "/prometheus");
}
}
And this are my dependencies:
<dependency>
<groupId>com.moelholm</groupId>
<artifactId>prometheus-spring-boot-starter</artifactId>
<version>1.0.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.prometheus/simpleclient -->
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient</artifactId>
<version>0.0.25</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.prometheus/simpleclient_hotspot -->
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient_hotspot</artifactId>
<version>0.0.25</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.prometheus/simpleclient_spring_boot -->
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient_spring_boot</artifactId>
<version>0.0.25</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.prometheus/simpleclient_servlet -->
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient_servlet</artifactId>
<version>0.0.25</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.hateoas</groupId>
<artifactId>spring-hateoas</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
It shows no error in the app, but when i am trying to access http://localhost:8787/prometheus i am getting Not Found.
Also i have tried only with actuator and it still the same.
http://localhost:8787/actuator, http://localhost:8787/health and etc. Allways getting: Not found.
So my question is what can cause this and how can i fix this problem?
I think that some of the dependencies is causing the problem. Try removing one by one and you can notice where is the problem.
Also for monitoring vert.x application here is a good example that can be useful for you.
About the jvm metrics, add this in your start:
DefaultExports.initialize();
new DropwizardExports(SharedMetricRegistries.getOrCreate("vertx")).register();

Spring boot custom starter , application doesn't find required bean

http://www.baeldung.com/spring-boot-custom-starter
I have followed tutorial and github example provided from the link above and have implemented similar way. I am using spring-boot-starter-parent :2.0.0.M3. Even after including my custom starter dependency in the pom for the app, it doesn't find required bean without #componentScan while deploying it.
It is giving following error.
APPLICATION FAILED TO START
Description:
Field fooApiCaller in com.core.controller.TestController required a bean of type 'service.ApiCaller' that could not be found.
Action:
Consider defining a bean of type 'service.ApiCaller' in your configuration.
Sample App ( one throwing error)
pom.xml
<dependency>
<groupId>abc.def</groupId>
<artifactId>custom-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
#Controller
public class FooController {
#Autowired
ApiCaller fooApiCaller
}
custom-starter module pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>abc.def</groupId>
<artifactId>custom-spring-boot-autoconfigure</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>abc.def</groupId>
<artifactId>myapi</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
Autoconfiguration module dependency
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>${spring-boot.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>abc.def</groupId>
<artifactId>myapi</artifactId>
<version>${project.version}</version>
<optional>true</optional>
</dependency>
</dependencies>
spring factories code
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
abc.def.myapi.autoconfigure.AutoConfiguration
MyAPI product
#Service
#Configuration
public class ApiCaller {
public String getName(String Id){return "name";}
}

Spring : Restrict injection of Repository module in Controller

I'm building a REST Webservice using Spring Boot (v 1.4.2.RELEASE). I'm trying to follow separation of concerns pattern, so I've created 3 maven projects,
myapp-repository, myapp-service and myapp-rest. myapp-service has a dependency of myapp-repository and myapp-rest has a dependency of myapp-service. Below is the initial configuration I've made.
myapp-repository
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
</dependencies>
Repository Config
#Configuration
#EnableJpaRepositories
#ComponentScan("com.mycompany.myapp.repository")
#EntityScan("com.mycompany.myapp.entity")
#PropertySource("classpath:repository.properties")
public class RepositoryConfig {
#Bean
#Primary
#ConfigurationProperties(prefix = "myapp.primary.datasource")
public DataSource getDataSource() {
return DataSourceBuilder.create().build();
}
}
myapp-service
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.4.RELEASE</version>
</dependency>
<dependency>
<groupId>com.mycompany.myapp</groupId>
<artifactId>myapp-repository</artifactId>
<version>0.0.1-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
Service config
#Configuration
#ComponentScan("com.mycompany.myapp.service")
#Import(RepositoryConfig.class)
#PropertySource("classpath:service.properties")
public class ServiceConfig {
}
myapp-rest
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.mycompany.myapp</groupId>
<artifactId>myapp-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
Rest config
#SpringBootApplication
#ComponentScan("com.mycompany.myapp.rest")
#Import(ServiceConfig.class)
public class RestConfig extends SpringBootServletInitializer {
/**
* #param args
*/
public static void main(String[] args) {
SpringApplication.run(RestConfig.class, args);
}
}
Now, I want to restrict my repository services to be autowired in myapp-rest, but with this current implementation, it's possible. Only services inside myapp-service module should be allowed to autowire in myapp-rest. Is it possible?

Katharsis in combination with Spring Boot

I have implemented a REST API using Spring Boot (version 1.3.6.RELEASE), which is working as expected. However I would like to add JSON API support to my application.
The problem is that I get a 404 when trying to execute a GET on a Katharsis resource.
The dependencies in pom.xml look as follows (I use Spring Security too):
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
<exclusion>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-integration</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.codehaus.woodstox</groupId>
<artifactId>woodstox-core-asl</artifactId>
<version>4.4.1</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>${hsqldb.version}</version>
</dependency>
<!--SpringFox dependencies -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${springfox-version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${springfox-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-tools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>dumbster</groupId>
<artifactId>dumbster</artifactId>
<version>1.6</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.katharsis</groupId>
<artifactId>katharsis-spring</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.9</version>
</dependency>
</dependencies>
My application initialisation class is as follows:
#SpringBootApplication
#Configuration
#EnableAutoConfiguration(exclude = WebMvcAutoConfiguration.class)
#EnableSwagger2
#ComponentScan(basePackages = "com.myapp")
#Import({KatharsisConfigV2.class})
public class Application {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
}
}
The resource class:
#ApiModel(description = "")
#JsonApiResource(type = "foo-data")
public class FooData extends DomainRepresentation {
#JsonApiId
private String id = null;
#JsonProperty
private String name = null;
// .... getters & setters
}
ResourceRepository class:
#JsonApiResourceRepository(FooData.class)
#Component
public class FooDataKatApi extends MyApi {
#Autowired
private FooDataService fooDataService;
#JsonApiFindOne
public FooData foodataIdGet(String id, QueryParams requestParams) {
FooData result = fooDataService.getFooDataById(id);
return result;
}
}
If I add Spring #ResourceMappings than I get data back but without Katharsis additions like "link", etc. It's as if the API call is not being picked up by Katharsis, but it's handled by Spring.
Any help would be appreciated.
-- EDITTED --
The FooDataService is as follows:
#Service
public class FooDataService extends MyService {
#Autowired
private FooDataRepository fooDataRepository;
public FooData getFooDataById(String id) {
FooDataEnt fooDataEnt = fooDataRepository.findByFooDataId(id);
if (fooDataEnt != null) {
return convertFooDataEntToFooData.apply(fooDataEnt);
}
throw new NotFoundException("Foo not found");
}
}
The FooDataRepository extends Spring's PagingAndSortingRepository.
Katharsis config in application.yaml:
katharsis:
resourcePackage: com.my.package
domainName: http://localhost:8080
pathPrefix: /api/kat
The request and response from PostMan
-- UPDATE 1 --
Apparently the configured value for katharsis.pathPrefix was not correct. Web application's context-root is "/api" and the value of katharsis.pathPrefix should be only "/kat".
My next problem is that a RepositoryNotFoundException is being throw while handling the request, while the Resource class is found already.
I don't see your foo data service implementation anywhere. However, I am 99% sure you're not passing the json api accept type.
Accept: application/vnd.api+json
I solved the riddle by debugging the code and finding out that my Katharsis config was not correct. Katharsis only picked up the resource classes but not the resource repository classes. When I changed the katharsis.resourcePackage to a higher level where the resource repositories resided, the problem got solved and Katharsis picked up all related annotated classes.

Categories