I am developing a little demo project with Spring MVC on a Tomcat with hibernate and JSPs. The application was working with thymeleaf as a view resolver but I need to rewrite my thymeleaf template as a .JSP. So I needed to reconfig everything. I am also trying to only use annotation configuration files without any xml.
The problem is that I am seeing the source code of my JSP-File without resolving.
The Request-Mapping and the program logic already worked with thymeleaf + spring. I am getting no error messages in the log files. I tried a lot of changes so my config files may be inconsistent at the moment. Any pointers or advice is appreciated.
My config files are below:
MyWebAppInitializer:
public class MyWebAppInitializer implements WebApplicationInitializer {
private static final String CONFIG_LOCATION = "MvcConfiguration";
private static final String MAPPING_URL = "/";#Override
public void onStartup(ServletContext servletContext) throws ServletException {
WebApplicationContext context = getContext();
servletContext.addListener(new ContextLoaderListener(context));
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("DispatcherServlet", new DispatcherServlet(context));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping(MAPPING_URL);
}
private AnnotationConfigWebApplicationContext getContext() {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.setConfigLocation(CONFIG_LOCATION);
return context;
}
}
MvcConfiguration:
class MvcConfiguration extends WebMvcConfigurerAdapter {
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
BenutzerController:
#Controller
public class BenutzerController {
#Autowired
BenutzerRepository repository;
#ModelAttribute("Benutzer")
public Benutzer loadEmptyModelBean() {
return new Benutzer();
}
#ModelAttribute("userList")
public List < Benutzer > userList() {
return toList(repository.findAll());
}
#RequestMapping("/verwaltung")
public String verwaltung(#RequestParam(value = "message", required = false, defaultValue = "Defaultvalue") String message, ModelMap model) {
model.addAttribute("message", message);
return "verwaltung";
}
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<name>benutzerverwaltung</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
EDIT: SOLUTION
editing the pom.xml:
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<version>8.0.29</version>
</dependency>
Are you using Spring Boot's embedded Tomcat? According to the answer to this question, you may need to add a dependency: compile("org.apache.tomcat.embed:tomcat-embed-jasper"). However, I've never got JSPs to work properly with an embedded tomcat - you can create a war file instead, as it says in the docs.
Related
I am trying to configure Keycloak with spring boot. But the endpoints that I configure wether its open or with a Role I walys get a 401
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true,
jsr250Enabled = true)
public class KeycloakSecurityConfig extends
KeycloakWebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests()
.antMatchers("/test/anoymous").permitAll();
.antMatchers("/test/user").hasAnyRole("user")
.antMatchers("/test/admin").hasAnyRole("admin")
.antMatchers("/test/all-user").hasAnyRole("user","admin")
.anyRequest()
http.csrf().disable();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
#Bean
#Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
#Bean
public KeycloakConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
}
When I hit the test endpoint anonymous I get back
{
"timestamp": "2021-07-08T20:39:21.265+0000",
"status": 401,
"error": "Unauthorized",
"message": "Unauthorized",
"path": "/test/anonymous"
}
However even with the keycloak token I get an error which is not authorized... The same as above but with Bearer Token.
#RestController
#RequestMapping("/test")
public class KeyController {
#RequestMapping(value="/anonymous", method=RequestMethod.GET)
public ResponseEntity<String> AdminEndpoint() {
return ResponseEntity.ok("Hello Anounymous");
}
#RolesAllowed("user")
#RequestMapping(value="/user", method=RequestMethod.GET)
public ResponseEntity<String> getUser(){
return ResponseEntity.ok("Hello User");
}
#RequestMapping(value="/admin", method=RequestMethod.GET)
public ResponseEntity<String> getAdmin(){
return ResponseEntity.ok("Hello Admin");
}
#RequestMapping(value="/all-users", method=RequestMethod.GET)
public ResponseEntity<String> getAllUsers(){
return ResponseEntity.ok("Hello to all");
}
}
It runs normally but I checked every spring security configuration on stack as possible as I can but nothing worked. Please help me.
This is the Pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.io.keycloak</groupId>
<artifactId>keycloak</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<spring.version>5.3.4</spring.version>
<keycloak.version>14.0.0</keycloak.version>
<java.version>11</java.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</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-security</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-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
<version>${keycloak.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
I figured it out ...
1 - The class RestController was not being found because it was in another package. So at the main class where the main function is I inputed #ComponentScan for where the RestController was.
#SpringBootApplication
#ComponentScan("com.io*") //This was the issue...
public class mainApp {
public static void main(String[] args) {
//Hello
SpringApplication.run(mainApp.class, args);
}
}
Just an FYI. Even with the #RestController, #Component, #Controller and other annotations where automatically spring would find does not actually work that way. You sometimes need to input #ComponentScan as well.
The result:
I work with a Spring microservice and received the following errors,
2020-01-20 09:58:22.504 ERROR 13758 --- [nio-8080-exec-1] o.a.c.c.C.[.[localhost].[/].[jsp] : Servlet.service() for servlet [jsp] threw exception
java.lang.ClassNotFoundException: org.apache.tomcat.util.security.Escape
at java.net.URLClassLoader.findClass(URLClassLoader.java:382) ~[na:1.8.0_211]
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_211]
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349) ~[na:1.8.0_211]
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_211]
at org.apache.jasper.compiler.JspUtil.getExprInXml(JspUtil.java:85) ~[tomcat-embed-jasper-9.0.29.jar:9.0.29]
at org.apache.jasper.compiler.PageDataImpl$SecondPassVisitor.printAttributes(PageDataImpl.java:736) ~[tomcat-embed-jasper-9.0.29.jar:9.0.29]
In the browser, its provided the error,
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Mon Jan 20 09:58:22 BDT 2020
There was an unexpected error (type=Internal Server Error, status=500).
org/apache/tomcat/util/security/Escape
I provide a few code snippets from the respective micro-service,
#SpringBootApplication
#EnableCircuitBreaker
#EnableDiscoveryClient
#EnableFeignClients
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
}
The controller class,
#Controller
#Transactional
#RequestMapping("/website/vehicles")
public class VehicleController {
#Autowired
private VehicleRepository data;
#Autowired
private PositionTrackingExternalService externalService;
#PostMapping(value = "/newVehicle.html")
public String newVehicle(Vehicle vehicle) {
data.save(vehicle);
return "redirect:/website/vehicles/list.html";
}
#PostMapping(value = "/deleteVehicle.html")
public String deleteVehicle(#RequestParam Long id) {
data.delete(id);
return "redirect:/website/vehicles/list.html";
}
#GetMapping(value = "/newVehicle.html")
public ModelAndView renderNewVehicleForm() {
Vehicle newVehicle = new Vehicle();
return new ModelAndView("newVehicle", "form", newVehicle);
}
#GetMapping(value = "/list.html")
public ModelAndView vehicles() {
List<Vehicle> allVehicles = data.findAll();
return new ModelAndView("allVehicles", "vehicles", allVehicles);
}
...... ..... ...... ..... ...... .....
...... ..... ...... ..... ...... .....
}
The feign client,
#FeignClient(name = "fleetman-position-tracker")
public interface RemotePositionMicroserviceCalls {
#GetMapping(value = "/vehicles/{name}")
public Position getLatestPositionForVehicle(#PathVariable(value = "name") String name);
}
The service classes,
#Service
public class PositionTrackingExternalService {
#Autowired
private ObjectProvider<RemotePositionMicroserviceCalls> remoteService;
#Autowired
private VehicleRepository repository;
#HystrixCommand(fallbackMethod = "handleExternalServiceDown")
public Position getLatestPositionForVehicleFromRemoteMicroservice(String name) {
Position response = remoteService.getObject().getLatestPositionForVehicle(name);
response.setUpToDate(true);
return response;
}
public Position handleExternalServiceDown(String name) {
// Read the last known position for this vehicle
Position position = new Position();
Vehicle vehicle = repository.findByName(name);
position.setLat(vehicle.getLat());
position.setLongitude(vehicle.getLongitude());
position.setTimestamp(vehicle.getLastRecordedPosition());
position.setUpToDate(false);
return position;
}
}
The project structure,
As requested, the pom.xml file is provided below,
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.transport.visualizer</groupId>
<artifactId>transport-visualizer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>TransportVisualizer</name>
<description>Vehicle Transport Visualizer</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Camden.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<resources>
<resource>
<filtering>true</filtering>
<directory>src/main/resources</directory>
<includes>
<include>application.properties</include>
</includes>
</resource>
</resources>
</build>
</project>
What's the issue here and how do I solve it?
Change your jasper dependency as
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
The dependency should be configured as with scope provided:
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
I am currently working on a project and I have to deal with Spring Boot and keycloak.
I want a configuration that is in the application.properties of spring.
Here is a part of my configuration file:
keycloak.enabled = true
keycloak.auth-server-url=${SSO_URL:http://MYIP:8082/auth/}
keycloak.realm=${SSO_REALM:approfox-dev}
keycloak.resource=${SSO_CLIENT:approfox-dev-login}
keycloak.ssl-required=none
keycloak.public-client=true
keycloak.principal-attribute=preferred_username
But when I try to access to any API endpoint, I got an 500 Internal Server Error with juste a NullPointerException. I do not know from where or why this exception occures. It seems that the application properties file is not loading by keycloak because when I use keycloack.json and the method that load it, it works.
#Configuration
#EnableWebSecurity
#KeycloakConfiguration
#ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
#ConditionalOnProperty(
value = "keycloak.enabled",
havingValue = "true",
matchIfMissing = false
)
class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
SimpleAuthorityMapper grantedAuthorityMapper = new SimpleAuthorityMapper();
grantedAuthorityMapper.setPrefix("ROLE_");
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(grantedAuthorityMapper);
auth.authenticationProvider(keycloakAuthenticationProvider);
}
#Bean
#Override
#ConditionalOnMissingBean(HttpSessionManager.class)
protected HttpSessionManager httpSessionManager() {
return new HttpSessionManager();
}
// Keycloak Spring Boot resolver not working
#Bean
public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
#Bean
#Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(
new SessionRegistryImpl());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.csrf()
.disable()
.cors()
.and()
.authorizeRequests()
.antMatchers("/exemple1")
.hasRole("student")
.antMatchers("/exemple2")
.hasRole("admin")
.anyRequest()
.permitAll();
}
// keycloak.json working...
/**
* Overrides default keycloak config resolver behaviour (/WEB-INF/keycloak.json) by a simple mechanism.
* <p>
* This example loads other-keycloak.json when the parameter use.other is set to true, e.g.:
* {#code ./gradlew bootRun -Duse.other=true}
*
* #return keycloak config resolver
*/
/*#Bean
public KeycloakConfigResolver keycloakConfigResolver() {
return new KeycloakConfigResolver() {
private KeycloakDeployment keycloakDeployment;
#Override
public KeycloakDeployment resolve(HttpFacade.Request facade) {
if (keycloakDeployment != null) {
return keycloakDeployment;
}
String path = "/keycloak.json";
InputStream configInputStream = getClass().getResourceAsStream(path);
if (configInputStream == null) {
throw new RuntimeException("Could not load Keycloak deployment info: " + path);
} else {
keycloakDeployment = KeycloakDeploymentBuilder.build(configInputStream);
}
return keycloakDeployment;
}
};
}*/
}
I have searched all over internet I can't find anything about that issue...
My POM.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
</parent>
<groupId>xxx</groupId>
<artifactId>xxxx</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>xxxx</name>
<description>xxxx</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
<version>8.0.1</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-adapter</artifactId>
<version>8.0.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.keycloak.bom</groupId>
<artifactId>keycloak-adapter-bom</artifactId>
<version>3.3.0.Final</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- <plugin>-->
<!-- <artifactId>maven-assembly-plugin</artifactId>-->
<!-- <version>3.1.1</version>-->
<!-- <configuration>-->
<!-- <descriptorRefs>-->
<!-- <descriptorRef>project</descriptorRef>-->
<!-- </descriptorRefs>-->
<!-- </configuration>-->
<!-- <executions>-->
<!-- <execution>-->
<!-- <id>make-assembly</id>-->
<!-- <phase>package</phase>-->
<!-- <goals>-->
<!-- <goal>single</goal>-->
<!-- </goals>-->
<!-- </execution>-->
<!-- </executions>-->
<!-- </plugin>-->
</plugins>
</build>
</project>
I am getting a NullPointerException on an autowired bean in a service class. The class I'm trying to autowire is a Cassandra Repository.
My main class Application.java
#SpringBootApplication
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
My Cassandra configuration CassandraConfig.java
#Configuration
#EnableCassandraRepositories(basePackages = "com.myretail")
public class CassandraConfig extends AbstractCassandraConfiguration {
#Override
protected String getKeyspaceName() {
return "myretail";
}
#Bean
public CassandraClusterFactoryBean cluster() {
CassandraClusterFactoryBean cluster =
new CassandraClusterFactoryBean();
cluster.setContactPoints("127.0.0.1");
cluster.setPort(9042);
return cluster;
}
#Bean
public CassandraMappingContext cassandraMapping()
throws ClassNotFoundException {
return new BasicCassandraMappingContext();
}
#Bean
public ProductService productService() {
return new ProductService();
}
}
My repository (dao) ProductPriceRepository.java
public interface ProductPriceRepository extends CassandraRepository<ProductPrice> {
#Query("select * from productprice where productId = ?0")
ProductPrice findByProductId(String productId);
}
My service class ProductService.java
#Path("/product")
#Component
public class ProductService {
#Autowired
ProductPriceRepository productPriceRepository;
#GET
#Path("/{id}")
#Produces(MediaType.APPLICATION_JSON)
public Product getTargetProduct(#PathParam("id") String productId) {
String urlString = "https://api.vendor.com/products/v3/" + productId + "?fields=descriptions&id_type=TCIN&key=43cJWpLjH8Z8oR18KdrZDBKAgLLQKJjz";
JSONObject json = null;
try {
json = new JSONObject(JsonReader.getExternalJsonResponse(urlString));
} catch (JSONException e) {
e.printStackTrace();
}
Product product = new Product();
product.setId(productId);
try {
JSONObject productCompositeResponse = json.getJSONObject("product_composite_response");
JSONArray items = productCompositeResponse.getJSONArray("items");
JSONObject item = items.getJSONObject(0);
JSONObject onlineDescription = item.getJSONObject("online_description");
product.setName(onlineDescription.getString("value"));
} catch (JSONException e) {
e.printStackTrace();
}
ProductPrice productPrice = productPriceRepository.findByProductId(productId);
product.setProductPrice(productPrice);
return product;
}
}
My pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.myretail</groupId>
<artifactId>MyRetail</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>MyRetail</name>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>com.datastax.cassandra</groupId>
<artifactId>cassandra-driver-core</artifactId>
<version>2.1.5</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-cassandra</artifactId>
<version>1.4.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.cassandraunit</groupId>
<artifactId>cassandra-unit-spring</artifactId>
<version>2.1.9.2</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.cassandraunit</groupId>
<artifactId>cassandra-unit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.cassandraunit</groupId>
<artifactId>cassandra-unit-shaded</artifactId>
<version>2.1.9.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hectorclient</groupId>
<artifactId>hector-core</artifactId>
<version>2.0-0</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-servlet</artifactId>
<version>1.18.3</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
<version>1.18.3</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>1.3.6.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<url>http://localhost:8080/manager/text</url>
<server>my-tomcat</server>
<path>/myRetail</path>
</configuration>
</plugin>
</plugins>
</build>
</project>
It is my understanding that the annotations should pick up the repository and create the bean based off of the #EnableCassandraRepositories annotation. The #Autowired ProductPriceRepository in ProductService.java is always null though when I run this on tomcat. HOWEVER, if I run a junit test against the service call, the bean is properly created, the object is not null, and the tests pass (via #ContextConfiguration annotation).
I've looked at a couple different patterns that I thought might help, but none of them have worked. I can't create an implementation of my interface because Cassandra handles that internally and I'm forced to implement the Cassandra methods.
I feel like something is just slightly off with the annotations somewhere. Any ideas?
The problem is with your pom.xml
For spring-boot Cassandra application, you have to include below dependencies and parent pom in pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.5.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</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-cassandra</artifactId>
</dependency>
</dependencies>
I'm trying to return xml from my #RestController method -
#RestController
public class MCSController {
.
.
#RequestMapping(value = "/encoders", method = { RequestMethod.GET }, produces = { MediaType.APPLICATION_JSON,
MediaType.APPLICATION_XML })
public List<EncoderVO> getEncoders() {
List<EncoderVO> encoders = null;
try {
encoders = infoService.listEncoders();
} catch (MCSException e) {
logger.error("Error in listing encoders : " + e.getMessage());
}
return encoders;
}
Here is my EncoderVO.java -
#XmlRootElement
public class EncoderVO {
#XmlElement
private Long id;
#XmlElement
private String name;
#XmlElement
private Boolean flagActive;
public EncoderVO() {
}
public EncoderVO(Long id, String name, Boolean flagActive) {
super();
this.id = id;
this.name = name;
this.flagActive = flagActive;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Boolean getFlagActive() {
return flagActive;
}
public void setFlagActive(Boolean flagActive) {
this.flagActive = flagActive;
}
}
This is my pom.xml file -
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test</groupId>
<artifactId>mcs</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<!-- Inherit defaults from Spring Boot -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.0.RELEASE</version>
</parent>
<properties>
<aws.sdk-version>1.9.1</aws.sdk-version>
<liquibase.version>3.3.0</liquibase.version>
</properties>
<!-- Add typical dependencies for a web application -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>jackson-annotations</artifactId>
<groupId>com.fasterxml.jackson.core</groupId>
</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-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</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>
<exclusions>
<exclusion>
<artifactId>jackson-annotations</artifactId>
<groupId>com.fasterxml.jackson.core</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-broker</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<!-- Aws SDK Dependencies -->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-s3</artifactId>
<version>${aws.sdk-version}</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-elastictranscoder</artifactId>
<version>${aws.sdk-version}</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-sqs</artifactId>
<version>${aws.sdk-version}</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-sns</artifactId>
<version>${aws.sdk-version}</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-datapipeline</artifactId>
<version>${aws.sdk-version}</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-cloudfront</artifactId>
<version>${aws.sdk-version}</version>
</dependency>
</dependencies>
</project>
Below is my Application class -
#SpringBootApplication(exclude = { SpringBootWebSecurityConfiguration.class, LiquibaseAutoConfiguration.class })
#ComponentScan(basePackages = { "com.test.ott.mcs" })
#EnableAspectJAutoProxy
#EnableJms
#EntityScan("com.test.ott.mcs.entities")
#EnableJpaRepositories("com.test.ott.mcs.repository")
public class MCSApplication {
#Bean
JmsListenerContainerFactory<?> jmsContainerFactory(ConnectionFactory connectionFactory) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
// A core poll size of 3 threads and a maximum pool size of 10 threads
factory.setConcurrency("3-10");
return factory;
}
// Using factory pattern with spring annotation
#Bean
public FactoryBean serviceLocatorFactoryBean() {
ServiceLocatorFactoryBean factoryBean = new ServiceLocatorFactoryBean();
factoryBean.setServiceLocatorInterface(EncodingAPIFactory.class);
return factoryBean;
}
public static void main(String args[]) {
SpringApplication.run(MCSApplication.class, args);
}
}
When I hit the url /encoders in browser, i get the below error -
There was an unexpected error (type=Not Acceptable, status=406). Could
not find acceptable representation
The jackson related jars in my calsspath are -
jackson-core-asl : 1.9.13
jackson-jaxrs : 1.9.13
jackson-mapper-asl : 1.9.13
jackson-annotations : 2.6.3
jackson-core : 2.6.3
jackson-module-jaxb-annotations : 2.2.3
jackson-jaxrs-json-provider : 2.2.3
jackson-jaxrs-base : 2.5.4
jackson-databind : 2.6.3
So, I have MappingJackson2HttpMessageConverter in my classpath.
Please suggest. Thanks in advance.
There is a solution that will work out-of-the-box, similarly to JAX-RS but with a bit worse output. The solution uses jackson-dataformat-xml. Add dependency to your project:
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
Response will look like this:
<?xml version="1.0" encoding="UTF-8"?>
<List>
<item>
<id>1</id>
<name>testEncoder1</name>
<flagActive>true</flagActive>
</item>
<item>
<id>2</id>
<name>testEncoder2</name>
<flagActive>true</flagActive>
</item>
<item>
<id>3</id>
<name>testEncoder3</name>
<flagActive>true</flagActive>
</item>
</List>
For further details please look at Spring MVC Way (jackson-dataformat-xml)
try
http://localhost:8080/mcs-0.0.1-SNAPSHOT/encoders.
mcs is the name of the application and
0.0.1-SNAPSHOT the version.
If it doesn't works you have to add a global path into the RequestController. Something like:
#RestController
#RequestMapping(value = "/mcs")
public class MCSController {
.
.
#RequestMapping(value = "/encoders", method = { RequestMethod.GET }, produces = { MediaType.APPLICATION_JSON,
MediaType.APPLICATION_XML })
public List<EncoderVO> getEncoders() {
and this request:
http://localhost:8080/mcs-0.0.1-SNAPSHOT/mcs/encoders
i hope it helps you.
Cheers
Add this dependecy in you POM.xml
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.8</version>
problem is with version of this jar. so please try out this solution