Spring AOP blocks RestController - java

I try to learn Spring AOP. I've created simple spring boot project in IDEA.
Service.java
package com.example.demo.service;
//imports..
public interface Service {
public DataEntity getData();
}
ServiceImpl.java
package com.example.demo.service;
//imports..
#RestController("service")
public class ServiceImpl implements Service {
#RequestMapping(value="/test", method= RequestMethod.GET)
public DataEntity getData() {
DataEntity data = new DataEntity();
data.setData("SomeString");
return data;
}
}
ServiceCallingAspect.java
package com.example.demo.aspects;
//imports..
#Aspect
#EnableAspectJAutoProxy
#Component
public class ServiceCallingAspect {
private Log log = LogFactory.getLog(ServiceCallingAspect.class);
#AfterReturning("execution(public * com.example.demo.service.*.*(..))")
public void logBeforeRestCall(JoinPoint pjp) throws Throwable {
log.info(" POST REST call " + pjp);
}
}
DemoApplication.java
package com.example.demo;
//..
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
So when I try to call my rest service on http://localhost:8080/test, I get something like that.
{
"timestamp": 1514109432038,
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/test"
}
When I disable my aspect (just comment all annotations in ServiceCallingAspect.java) the service works perfectly. Can you show me where I am wrong?

Change #EnableAspectJAutoProxy to #EnableAspectJAutoProxy(proxyTargetClass=true).
#Aspect
#EnableAspectJAutoProxy(proxyTargetClass=true)
#Component
public class ServiceCallingAspect {
.....
}

Related

Can not access my spring boot application by url

I try to access my endpoint with local host url - http://localhost:8080/all
this is my Application.java file
package com.example.MyApplication;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication .class, args);
}
}
and this is my end point
#RestController("GetAll")
#RequestMapping("/all")
public class GetAll {
private final DataService dataService;
#Autowired
public GetAll (DataService dataService) {
this.dataService = dataService;
}
#GetMapping
public List<DataDto> getAll() {
return dataService.getAll();
}
}
and I try with this url - http://localhost:8080/all
{
"timestamp": "2022-10-06T15:27:18.574+00:00",
"status": 404,
"error": "Not Found",
"path": "/all"
}
This kind of problem might happen due to some components(like controller, service, etc) not being scanned by spring due to components and the Main class being in a different package. Here, Your main class is in com.example.MyApplication package. So If you keep all other components(like controller, service, etc) of the spring boot in the same package or sub-package then that will work as expected. If you want to keep those in the different packages you need to mention those different packages which are having spring components like controllers in the #ComponentScan annotation.
Change GetAll class's package declaration if you can keep them in the same package:
package com.example.MyApplication;
#RestController("GetAll")
#RequestMapping("/all")
public class GetAll {
private final DataService dataService;
#Autowired
public GetAll (DataService dataService) {
this.dataService = dataService;
}
#GetMapping
public List<DataDto> getAll() {
return dataService.getAll();
}
}
Reference:
https://www.baeldung.com/spring-component-scanning

Spring rest api - Get method problem with dots

I have problem when trying to create get method which allows dots as a parameter.
#GetMapping(path = "test/{id:.+}")
#ResponseBody
public String getTest(#PathVariable String id) {
return id;
}
So it works for example for path
test/core.txt
But it does not for
test/core.something
I got error like
{
"timestamp": 1623837131322,
"status": 500,
"error": "Internal Server Error",
"exception": "java.lang.NoClassDefFoundError",
"message": "Could not initialize class org.springframework.web.accept.PathExtensionContentNegotiationStrategy$ActivationMediaTypeFactory",
"path": "/api/v1/test/core.somethign"
}
java.lang.NoClassDefFoundError: Could not initialize class org.springframework.web.accept.PathExtensionContentNegotiationStrategy$ActivationMediaTypeFactory ...
Also tried to extend WebMvcConfigurationSupport with
#Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(false);
}
I am using spring boot version 1.5.22.RELEASE.
Do you have any idea what can be wrong, seems like my configuration is ignored somehow
package eu.test;
import org.springframework.context.annotation.*;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
#Configuration
#ComponentScan
#PropertySource(
ignoreResourceNotFound = false,
value = "classpath:application.properties")
public class ApplicationConfiguration extends WebMvcConfigurationSupport {
#Override
protected void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(false);
}
}
Add below bean in your appconfig file.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
#Configuration
public class MvcConfig extends WebMvcConfigurationSupport{
#Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping handlerMapping = super.requestMappingHandlerMapping();
handlerMapping.setUseSuffixPatternMatch(false);
handlerMapping.setUseTrailingSlashMatch(false);
return handlerMapping;
}
}
Update : This class is deprecated. Now you have to use below code. I tested it and i'm posting here.
#Configuration
public class ApplicationConfig extends WebMvcConfigurationSupport {
#Override
protected void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(false);
}
}
Output:
test/abc.tera : abc.tera
test/core.something : core.something

Autowiring returns a NullPointerException

I have an interface RestService and a RestServiceImpl class shown below:
//RestService:
public interface RestService {
public void printMessage();
}
//RestServiceImpl:
#Service
public class RestServiceImpl implements RestService {
public RestServiceImpl() {
}
public void printMessage() {
System.out.println("This is a test message.");
}
}
When testing the printMessage() method, I get a NullPointerException. I'm pretty sure I autowired everything correctly and have added the appropriate annotations to the classes. Not sure why this is happening.
#SpringBootTest
public class RestServiceTest {
#Autowired
RestService restService;
#Test
public void someTest() {
restService.printMessage(); //Thows NullPointerException
}
}
What am I missing here?
First of all, make sure the whole spring infrastructure is plugged in, a "bridge" between the JUnit framework and spring:
There is no #RunWith(SpringRunner.class) on the test:
#RunWith(SpringRunner.class)
#SpringBootTest
public class RestServiceTest {
#Autowired
RestService restService;
#Test
public void someTest() {
restService.printMessage(); //Thows NullPointerException
}
}
Add #RunWith(SpringRunner.class) at top of RestServiceTest.

Spring boot not displaying first view

I'm building a spring boot application. My problem is that when I run the project, my login page is not shown. This is my code:
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class RestLogin {
#RequestMapping("/")
public String login() {
return "login";
}
}
I get only a white page and "login" is written in it. When I try to change the #RestController with #Controller I get this GET http://localhost:8080/ 404 (). My login.html page is located under the webapp>tpl>login.html
How can I display my login page?
Edit
This is my application class
#SpringBootApplication
public class ExampleApplication extends SpringBootServletInitializer {
private static Logger logger = LoggerFactory.getLogger(ExampleApplication.class);
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(ExampleApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(ExampleApplication.class, args);
}
}
I dont know your configuration but:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().and().authorizeRequests()
.antMatchers("/**").permitAll();
http.authorizeRequests().antMatchers("/**").permitAll();
}
}
In the Application.properties file add:
spring.mvc.view.suffix: .html
Change #RestController to #Controller for RestLogin class. Also put your html file inside the static folder inside resources folder.
You need an application class with a main method. See this tutorial.
Here's a snippet:
package hello;
import java.util.Arrays;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
return args -> {
System.out.println("Let's inspect the beans provided by Spring Boot:");
String[] beanNames = ctx.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
System.out.println(beanName);
}
};
}
}
This is the normal behavior.
New version of Spring web comes with #RestController annotation which nothing but #Controller + #ResponseBody. So when you have a return statement in a method you must use #RestController or annotate your method with #ResponseBody.
Here the problem is that Spring don't know a lot about the http method type, can you please try to use #GetMapping("/") to combinbe path and method at the same time.
According to your posted code and your description, you're getting an expected behavior.
When you annotate your controller with #RestController, that means that your methods on that controller will try to return their result as JSON.
According to your code:
#RestController
public class RestLogin {
#RequestMapping("/")
public String login() {
return "login";
}
}
You're returning the String "login", that's why you're getting empty white page with the word login as JSON
If you will change the #RestController to #Controller then it no longer will return your string as JSON,
but Spring will try to figure out from the that "login" string a view, and for that you'll need to add a view resolver bean to your project.

Spring Cloud Config and static content

I have a application that uses Spring cloud config (--spring.profiles.active=native) and also serves up some html pages within the same application. All is fine until I introduce static resources (src/main/resources/css/bootstrap-switch.css). The URL calls to http://localhost:8080/css/bootstrap-switch.css fails with this Exception:
{"timestamp":1438114326940,"status":406,"error":"Not Acceptable","exception":"org.springframework.web.HttpMediaTypeNotAcceptableException","message":"Could not find acceptable representation","path":"/css/bootstrap-switch.css"}
When I disable the #EnableConfigServer, the URL returns the CSS content. I am on Spring Cloud Config version 1.0.2.
Here's my minimalist code that can reproduce this issue:
#SpringBootApplication
#EnableConfigServer
public class Application {
public static void main(String args[]) {
SpringApplication.run(ApplicationConfiguration.class, args);
}
}
#Configuration
#SpringBootApplication
class ApplicationConfiguration {
#Bean
public TestController testController() {
return new TestController();
}
#Bean
public MvcController mvcController() {
return new MvcController();
}
}
#RestController
class TestController {
#RequestMapping("/test")
#ResponseBody
public String test() {
return "hello world";
}
}
#Controller
class MvcController {
#RequestMapping("/landing")
public String landingPage() {
return "landing";
}
}
Config server by default has an api that matches /*/*. You can move the root of the api by changing spring.cloud.config.server.prefix=myroot.

Categories