Spring 3.2 #ControllerAdvice Not Working - spring-mvc

I am having trouble getting #ControllerAdvice to work. I updated my namespace location, which were 3.1 in my xml files. I moved the class with the controller to the same package as the controller. I am using 3.2.0 release jars. If I put the #ExceptionHandler annotation in the controller code, it works, but not in a separate class with the #ControllerAdvice. When the #ControllerAdvice class fails, I get my uncaught exception handler view. Anyone have ideas on how to trouble shoot this one?

If you use classpath scanning, probably you have to add new include filter to your <context:component-scan> element:
<context:include-filter type="annotation"
expression="org.springframework.web.bind.annotation.ControllerAdvice" />
Default scanning does not lookup this annotation, following spring-context-3.2.xsd for component-scan:
"Scans the classpath for annotated components that will be auto-registered as Spring beans. By default, the Spring-provided #Component, #Repository, #Service, and #Controller stereotypes will be detected."

For this problem, The first thing is confirming your config,
You need make sure that the #ControllerAdvice Class under your component-scan base package.
Make suer you use <mvc:annotation-driven/> in your spring-servlet.xml. or have #EnableWebMvc in your #ControllerAdvice Class
When you have the config right, the ControllerAdvice should already work, Now you said You got your uncaught exception handler view. I guess you got that in your InegrationTest, And you used mockMvc to test that, If so, you need put #WebAppConfiguration and build mokcMvc as follow:
#Autowired
private WebApplicationContext wac;
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
Using standaloneSetup(controller) will not work because lack of WebApplicationContext.

There is no extra configuration required. It should just work. Look at this link for more details. This provide very simple example:
https://javabeat.net/exception-controlleradvice-spring-3-2/
https://javabeat.net/controlleradvice-improvements-spring-4-0/

I had this same problem, in my case the problem was that there was a dependent library that had inside it a class with the #ControllerAdvice and #Order(Ordered.HIGHEST) annotation, to solve the problem I added the #Order(Ordered.HIGHEST) annotation in my classe, and now it works.
Since my exception class is in the same controller package spring gave my class higher priority even though both classes have the same #Order(Ordered.HIGHEST)
#ControllerAdvice
#Order(Ordered.HIGHEST)
public class RestResponseEntityExceptionHandler
extends ResponseEntityExceptionHandler {

I struggled with the same problem where my #ControllerAdvice class would not load while unit testing REST controllers' exceptions. If you are using spring boot (version 4) then you can use additional methods added by spring to load controller advice classes in standalone setting up your controllers.
mockMvc = MockMvcBuilders
.standaloneSetup(new YourRestController())
.setControllerAdvice(new ControllerAdviceClass())
.build();
This will straight-away initialize your controller advice class and your Junit test should be able to jump in to #ExceptionHandler methods defined in your controller advice class.

For me, #ControllerAdvice was not working at all cost. Even adding #EnableWebMvc or #WebAppConfiguration didn't make any change.
The way I was able make it working was,
adding #ExceptionHandler methods for my AbstractController class, the class that all the other controllers are extending upon.
I think #ControllerAdvice is supposed to do the same thing, i.e. compile the #ExceptionHandler methods defined under the class specified by #ControllerAdvice, into a common place where every controller can refer from. But unfortunately it was not working for me.

I solved it by defining ControlAdvice class in Configuration beans as shown below:
#Primary
#Bean
public RestResponseEntityExceptionHandler restResponseEntityExceptionHandler (){
return new RestResponseEntityExceptionHandler ();
}

Related

Wju a distinction in #RestController vs #Controller with regards to serving of static content in Spring Project?

After hours of reading different posts, example projects, and many different fixes, I solved an issue related to serving static content within my Spring Boot project- specifically errors I received from a link to a CSS in an html page. It was the less popular of two answers in this following link (excerpt below) that solved it for me.
Check the Controller classes for which annotation is used - #RestController or #Controller. Do not mix Rest API and MVC behaviour in one class. For MVC use #Controller and for REST API use #RestController
Spring Boot app not serving static content
In summary, after everything I tried (modifying application.properties to explicitly set static directory paths, moving the CSS file into many different folders, including the supposed standard set ones) the style sheet could not be found. BUT...Changing out #RestController for #Controller solved it for the following code.
#Controller
public class MVCController {
#Autowired
ThingdefstatsviewRepository defstatviewRepository;
#Autowired
ThingDefRecord thingDefRecord;
#GetMapping(path="/characterdef/{defid}")
public ModelAndView thymeLeafCharacterDefByID(#PathVariable String defid) {
Long id = Long.parseLong(defid);
thingDefRecord.loadAllStats(id);
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("CharacterPage.html");
//Adds an attribute to the model as a name/value(object) pair
modelAndView.addObject("thingstats", thingDefRecord);
return modelAndView;
}
}
Question is, why? What is it about using a ModelAndView object in a #RestController class that prevented my html page from loading the CSS file? Or the reverse, what is it about simply using #Controller that made this instantly work?
Clearly, as a novice with Spring, I am missing something about how these different Controllers function with linked static content, but can't find out why.
If you annotate a class with #RestController, you're telling Spring that you want to serialize an object and return it as JSON, or XML (definitely something other than an HTML page).
#Controller lets you choose to return an HTML page. (Or, if you additionally annotate your #RequestMapping / #GetMapping / #PostMapping with #ResponseBody, you can serialize an object and return it as JSON, or XML.)

ASP.NET Core MVC application dependency injection issue when using BaseController

Recently i tried to create a MVC application using ASP.NET Core 2.0 and i had some values defined in appsettings.json,
"MySettings": {
"WebApiBaseUrl": "http://localhost:6846/api/"
}
In order to read these values i have added
services.Configure<MySettingsModel>(Configuration.GetSection("MySettings"));
above line in ConfigureServices method in Startup.cs
and in my home controller i have added
private readonly IOptions<MySettingsModel> appSettings;
public HomeController(IOptions<MySettingsModel> app)
{
appSettings = app;
}
MySettingsModel class is just a model with property same as key define in appsettings.json.
by this method i'm able to read the value of this key.
Now my issue is that i want to use this key in many controllers so i don't want to repeat this code in every controller so what i did was i created a BaseConntroller, added its constructor and i got my values there. But when i inherit other controllers with my BaseController , it throws me an error and tells me to generate it's constructor, so basically it tells me to add constructor in every controller which is what i wanted to avoid.
How can i achieve this?
You can see the image for the error
And these are the potential fixes that it shows me.
This is just basic C# inheritance. Derived classes must re-implement constructors on base classes (at least the ones you want or need). The only exception is the empty constructor, which is implicit. In other words, you simply need:
public class HomeController : BaseController
{
public HomeController(IOptions<MySettingsModel> app)
: base(app)
{
}
And, of course, you need to change the accessibility of the base class field to protected instead of private. Otherwise, derived classes will not be able to access it.
Of course, this doesn't really save you that much. However, there's no free lunch here. Like I said, this is a limitation of C#, itself, so you have no choice. Although, it's worth mentioning, that while this can sometimes be annoying, it's actually a kind of useful feature of C#. You can look at any class and see exactly what constructors it has available, without having to trace down all its ancestors.
Actually, there is a good solution here:
https://stackoverflow.com/a/48886242/2060975
I am mostly using this method.
[Authorize]
[ApiController]
public abstract class ApiControllerBase : ControllerBase
{
private IOptions<AppSettings> _appSettings;
protected IOptions<AppSettings> appSettings => _appSettings ?? (_appSettings = (IOptions<AppSettings>)this.HttpContext.RequestServices.GetService(typeof(IOptions<AppSettings>)));
...
}
I hope it helps someone:)

Swagger Java class is not parsing properly

I am using swagger to create API documentation for one of my Spring Rest API project, but the swagger.json file created is having an issue.
One of my Super class is not getting converted properly.
Library used to implement the swagger is springfox. Please find the implementation details below.
Configuration
EnableWebMvc
EnableSwagger2
ComponentScan
public class MvcConfig extends WebMvcConfigurerAdapter {
}
This is the class causing the problem
public class ListResultModel MODEL extends BaseModel {
}
Json Created
"schema":{"$ref":"#/definitions/RedirectAttributes"}}],"responses":{"200":{"description":"OK","schema":{"type":"string"}},"201":{"description":"Created"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not Found"}}}},"/admin/migration/vat":{"get":{"tags":["migration-controller"],"summary":"vatMigration","operationId":"vatMigrationUsingGET","consumes":["application/json"],"produces":["/"],"parameters":[{"name":"retailerId","in":"query","description":"retailerId","required":true,"type":"string"}
{"$ref":"#/definitions/**ListResultModel«Item»"**}},"401":{"description":""},"403":{"description":"Forbidden"},"404":{"description":"Not Found"}}}},"/api/items/withoutPictures/{departmentId}/{vendorId}/{status}":{"200":{"description":"OK","schema":{"$ref":"#/definitions/**ListResultModel«Item»"}**},"401":{"description":""},"403":{"description":"Forbidden"},"404":{"description":"Not }
{"$ref":"#/definitions/ListResultModel«Lead»"}},"201":{"description":"Created"},"401":{"description":""},"403":{"description":"Forbidden"},"404":{"description":"Not Found"}}}}
I am trying to resolve this for a long time and there is no clue how to do it. Can anybody help me please!
Thanks in advance.
Vivek
This Got Fixed by the below Thread.
https://github.com/springfox/springfox/issues/1283
Regards
Vivek

Spring 4 AOP #Aspect isn't triggering for #RestController

I have created an Aspect which performs a basic id comparison to ensure that a user belongs to a the same group that created the entity being requested. I have had success attaching my aspect to #Service methods, but it doesn't make sense on the service layer, and I need it to be attached to #RestController methods instead. When I attempt to do this, everything seems good, but my Aspect never triggers, and the logs are silent.
pom.xml
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
spring context
<context:annotation-config/>
<context:component-scan base-package="my.pkg"/>
<aop:aspectj-autoproxy/>
<aop:config proxy-target-class="true"/>
Aspect
#Aspect
#Component
public class MyAspect {
#Pointcut("within(#org.springframework.stereotype.Controller *)")
public void controller() {}
#Pointcut("within(#org.springframework.web.bind.annotation.RestController *)")
public void restController() {}
#Pointcut("args(java.security.Principal,..)")
public void principalArgPointcut() {}
#Around("(controller() || restController()) && principalArgPointcut()")
public Object validate(ProceedingJoinPoint point) throws Throwable {
doValidationBefore();
Object result = point.proceed();
doValidationAfter();
return result;
}
}
where "doValidationBefore()" and "doValidationAfter()" will throw an exception if validation fails.
And finally, my RestController
#RestController
#RequestMapping("/my-path")
public class MyController {
#RequestMapping(value = "/{entityId}", method = RequestMethod.GET)
public #ResponseBody
ResponseEntity<MyEntity> getEntityDetails(Principal principal, #PathVariable("entityId") Long entityId) {
return new ResponseEntity(HttpStatus.OK);
}
}
Some things to note:
This exact aspect works when I change the execution pattern to match services and place it in my service package.
The Aspect and the RestController are in the same context
I use IDEA IDE, and when I use the "navigate to advised methods" icon on the Aspect, the method I'm testing IS listed in the list of methods.
None of the methods listed in "navigate to advised methods" are working
Things I have tried:
I added 3 libraries to my pom.xml: org.aspectj:aspectjrt:1.8.6,
org.aspectj:aspectjtools:1.8.6, cglib:cglib:2.2.2. None of these made
any difference.
I tried defining my Aspect and PointCuts directly in the context xml and removing the annotations, no difference.
I have tried setting my execution pattern to apply to ALL methods, and it still did not trigger.
I tried adding an interface for my RestController, no change.
I would love some help here, as I've been trying to solve this for quite some time now. I know it must be possible.
As it turns out, my Aspect and my Controllers were NOT, in fact, in the same context.
While I believed my Controllers to be included in the context scanning of my web-context.xml, they were actually being scanned in WEB-INF/servlet-context.xml
Once I moved my Aspect configuration to WEB-INF/servlet-context.xml, my Aspect began to trigger as expected.
Thanks for all those who contemplated my problem.
Figure out for sure where your service is being configured in spring. If you have I there is an icon that you can click to navigate to the spring bean config. Then ensure that the aspect is configured in the same file.
If they are definitely defined in the same file, look next that the aop pointcut advice matches the method on which you're expecting it to fire. Again, Idea has an icon next to the pointcut that will navigate to matching methods.

#Specializes for EJB

I'm trying to specialize an EJB. I have
package com.foo.core;
#Stateless
public class MyFacade { }
and
package com.foo.extension;
#Specializes
#Stateless
public class MyFacade extends com.foo.core.MyFacade { }
In my opinion, this should work, because the meaning of #Specializes is, that CDI should forget about the core-class and instead use the specialized class. I also found this bug https://issues.jboss.org/browse/WELD-1451 which indicates, that it is possible to specialize an EJB.
But if i try to deploy my application (I'm using Weblogic 12.1.3), I always get
weblogic.utils.ErrorCollectionException: There are 1 nested errors:
weblogic.j2ee.dd.xml.AnnotationProcessException: Duplicate ejb name
'MyFacade' found: annotation 'Stateless' on bean class
com.foo.core.MyFacade and annoation 'Stateless' on bean class
com.foo.extension.MyFacade
Am I doing anything wrong?
Thanks!
The exception message you quoted is caused by a name conflict, which is not directly related to CDI at all: each EJB can be addressed by a number of different JNDI names, and some of them (e.g. java:module/MyFacade) only include the simple class name, not the package name. So you cannot have two EJBs with the same name in different packages.
Adding CDI and #Specializes may prevent the specialized EJB from showing up in the CDI container, but it is still an EJB.
You can try to rename your derived class - this should solve the duplicate name issue, but I'm not sure it will solve your overall problem.

Resources