public class DefaultCountValidationInterceptor implements ValidateInterceptor
{
#Override
public void onValidate(final Object object, final InterceptorContext interceptorContext) throws InterceptorException
{
if (object instanceof BaseStoreModel)
{
final BaseStoreModel baseStoreModel = (BaseStoreModel) object;
if (baseStoreModel.getCount() < 0 || baseStoreModel.getCount() > 100)
{
throw new InterceptorException("Count should be between 0 and 100");
}
}
}
}
Interceptor Configuration:
<bean id="defaultCountValidationInterceptor"
class="se.istone.hybris.maersk.core.interceptors.DefaultCountValidationInterceptor " />
<bean id="defaultCountValidationInterceptorMapping"
class="de.hybris.platform.servicelayer.interceptor.impl.InterceptorMapping">
<property name="interceptor"
ref="defaultCountValidationInterceptor" />
<property name="typeCode" value="BaseStore" />
</bean>
Validation error message is displaying correctly in Hybris5.4 HMC, but
its not workinig in Hybris 6.7(1905) Backoffice
You are always getting default message due OOTB code in ModelSavingExceptionTranslationHandler.toString().
public class ModelSavingExceptionTranslationHandler extends ModelExceptionTranslationHandler {
public static final String I18N_UNEXPECTED_UPDATE_ERROR = "unexpected.update.error";
public boolean canHandle(Throwable exception) {
return exception instanceof ModelSavingException
|| exception instanceof ObjectSavingException && exception.getCause() instanceof ModelSavingException;
}
public String toString(Throwable exception) {
return this.getLabelByKey("unexpected.update.error");
}
}
When you are throwing InterceptorException Hybris internally throws ModelSavingException with your InterceptorException as Cause.
Backoffice exception are handled by ExceptionTranslationService, which contain list of Handlers to handle different kinds of Exceptions. For ModelSavingException, ModelSavingExceptionTranslationHandler is used.
Since OOTB Handler is straight up displaying default message, you can either override this class or you can create your own Exception Translation Handler and add it in the handlers list.
Documentation -> https://help.sap.com/viewer/5c9ea0c629214e42b727bf08800d8dfa/1905/en-US/8bc9570b86691014a901c290d2c5f107.html
It could be an error copying your code and configuration, but your InterceptorMapping there are errors with the bean ref, it is on capital letter
"DefaultCountValidationInterceptor "
instead of
"defaultCountValidationInterceptor "
Apart from that, you should remove the blank spaces at the end of the bean ids and class attributes of beans declared.
I've been trying to reproduce your error on 1905 Hybris OOTB code, but I cannot reproduce it, I tried it with the AddressValidator (which implement ValidatorInteceptor as well), getting the message from the exception shown on the error alert on backoffice:
Link to Backoffice address validation error alert image
The problem could be if an exception different from InterceptorException is thrown, like a nullPointerException, are you sure of having the count attribute filled an being not null?
It could be obvius, but if any of the attributes on the baseStore is changed, and then saved, the validation interceptor will be runned. My advice is checking nulls before accessing the count attribute for not getting an error, like:
if (baseStoreModel.getCount() !=null && (baseStoreModel.getCount() < 0 || baseStoreModel.getCount() > 100))
Doing the condition on this way will avoid the null problem, because if you're having the count attribute set to null, the condition will exit as soon as the first condition is evaluated as false (baseStoreModel.getCount() != null).
Another way to avoid the null error is having a defaultValue on your *-items.xml definition, adding a:
<defaultvalue>Integer.valueOf(0)</defaultvalue>
#JagadeeshKumar, as #Zaheer Attar has said on his answer https://stackoverflow.com/a/62415830/3346298 (really good point), you could have your own ModelExceptionTranslation Handler. But I would check, before customising anything, what is the error, I mean, what is the exception recieved on the
de.hybris.platform.platformbackoffice.services.handlers.ModelSavingExceptionTranslationHandler
Use a debug point there to check the content of the exception, the cause and even finding out if your message from your validator is there.
Once you know the exception you could know the real reason of why the OOTB TranslationHandler is not working as expected.
Developing a new Handler could not solve the root reason of the error which could create adjacent problems in the next future.
I tried, it works. Beside you overrided or create new handlers, you also need to add configuration like "remove" original handlers
Related
I am using Spring Cloud SQS messaging for listening to a specified queue. Hence using #SqsListener annotation as below:
#SqsListener(value = "${QUEUE}", deletionPolicy = SqsMessageDeletionPolicy.ALWAYS )
public void receive(#Headers Map<String, String> header, #Payload String message) {
try {
logger.logInfo("Message payload is: "+message);
logger.logInfo("Header from SQS is: "+header);
if(<Some condition>){
//Dequeue the message once message is processed successfully
awsSQSAsync.deleteMessage(header.get(LOOKUP_DESTINATION), header.get(RECEIPT_HANDLE));
}else{
logger.logInfo("Message with header: " + header + " FAILED to process");
logger.logError(FLEX_TH_SQS001);
}
} catch (Exception e) {
logger.logError(FLEX_TH_SQS001, e);
}
}
I am able to connect the specified queue successfully and read the message as well. I am setting a message attribute as "Key1" = "Value1" along with message in aws console before sending the message. Following is the message body:
{
"service": "ecsservice"
}
I am expecting "header" to receive a Map of all the message attributes along with the one i.e. Key1 and Value1. But what I am receiving is:
{service=ecsservice} as the populated map.
That means payload/body of message is coming as part of header, although body is coming correctly.
I wonder what mistake I am doing due to which #Header header is not getting correct message attributes.
Seeking expert advice.
-PC
I faced the same issue in one of my spring projects.
The issue for me was, SQS configuration of QueueMessageHandlerFactory with Setting setArgumentResolvers.
By default, the first argument resolver in spring is PayloadArgumentResolver.
with following behavior
#Override
public boolean supportsParameter(MethodParameter parameter) {
return (parameter.hasParameterAnnotation(Payload.class) || this.useDefaultResolution);
}
Here, this.useDefaultResolution is by default set to true – which means any parameter can be converted to Payload.
And Spring tries to match your method actual parameters with one of the resolvers, (first is PayloadArgumentResolver) - Indeed it will try to convert all the parameters to Payload.
Source code from Spring:
#Nullable
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
if (resolver.supportsParameter(parameter)) {
result = resolver;
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
}
How I solved this,
The overriding default behavior of Spring resolver
factory.setArgumentResolvers(
listOf(
new PayloadArgumentResolver(converter, null, false),
new HeaderMethodArgumentResolver(null, null)
)
)
Where I set, default flag to false and spring will try to convert to payload only if there is annotation on parameter.
Hope this will help.
Apart from #SqsListener, you need to add #MessageMapping to the method. This annotation will helps to resolve method arguments.
I had this issue working out of a rather large codebase. It turned out that a HandlerMethodArgumentResolver was being added to the list of resolvers that are used to basically parse the message into the parameters. In my case it was the PayloadArgumentResolver, which usually always resolves an argument to be the payload regardless of the annotation. It seems by default it's supposed to come last in the list but because of the code I didn't know about, it ended up being added to the front.
Anyway, if you're not sure take a look around your code and see if you're doing anything regarding spring's QueueMessageHandler or HandlerMethodArgumentResolver.
It helped me to use a debugger and look at HandlerMethodArgumentResolver.resolveArgument method to start tracing what happens.
P.S. I think your #SqsListener code looks fine except that I think #Headers is supposed to technically resolve to a Map of < String, Object >", but I'm not sure that would cause the issue you're seeing.
I'm using Spring Validation within a Spring MVC application that delegates validation to Hibernate Validator 5. I'm successfully able to have beans validated and have the messages interpolated by the validator. However, it's important that I also be able to have access to the message template itself, pre-interpolation.
For example, in some bean I have validation #Size(min=5,max=15,message="{my.custom.message}". In a messages.properties file I have entry my.custom.message=test min {min} and max {max}. In my BindingResult, I see the ObjectError with error message "test min 5 and max 15", but I need to look a value up at this point based on the non-interpolated my.custom.message raw value.
Can this be done? If it can't out of the box, can someone point me in the right direction for how I might customize spring's LocalValidatorFactoryBean to preserve this?
Update
I'm looking at extending org.springframework.validation.beanvalidation.SpringValidatorAdapter, and wrapping the getArgumentsForConstraint to automatically append the pre-interpolated message to the returned list of arguments. The notion of exactly what these 'arguments' are and how they're used is unclear to me, but if it's purely used for message interpolation, it seems relatively safe for me to append at the end. Any reason this might not work? Problems it might cause? Better ideas?
Solution
Didn't find any great solutions other than my 'update' above, so I ended up subclassing LocalValidatorFactoryBean with this:
#Override
protected Object[] getArgumentsForConstraint(String objectName, String field, ConstraintDescriptor<?> descriptor) {
if (null == descriptor) return super.getArgumentsForConstraint(objectName, field, descriptor);
Object[] orig = super.getArgumentsForConstraint(objectName, field, descriptor);
if (null == orig || orig.length < 1) return new Object[] { descriptor };
Object[] retval = new Object[orig.length+1];
System.arraycopy(orig, 0, retval, 0, orig.length);
retval[retval.length-1] = descriptor;
return retval;
}
In subsequent code, I look at the last object in this array and test to see if it's an instance of ConstraintDescriptor. Good enough I suppose.
However, it's important that I also be able to have access to the message template itself, pre-interpolation.
In which context do you need to access the template? If it is after validation, then getMessageTemplate() on ConstraintViolation gives you this. If it is within a constraint validator implementation, then you could use getDefaultConstraintMessageTemplate() on ConstraintValidatorContext.
I have an exception handling in my application very similar to this solution:
http://www.devcurry.com/2012/06/aspnet-mvc-handling-exceptions-and-404.html
There is a nasty bug in my app where it is possible for the sql to deadlock with an other process. This happens rarely (1-2 requests fail daily because of this), but it still happens.
How can I automatically refresh the page on sql deadlock (and hide the error this way from the end user on get requests)?
Can I do it in the Application_Error function? Or in the overridden OnException in HandleErrorAttribute?
EDIT:
I mocked up some code in the BaseController I created:
protected override void OnException(ExceptionContext filterContext)
{
Exception ex = filterContext.Exception;
SqlException sex = ex as SqlException;
if (sex != null && sex.Number == 1205)
{
Log.Error("Transaction deadlocked with the following exception:");
Log.Exception(sex);
//I need to write the logic that refreshes the page here.
}
else
{
Log.Error("Application error with the following exception:");
Log.Exception(ex);
}
base.OnException(filterContext);
}
I need help on the refresh part.
I would deal with it by overriding the OnException() method of the controller. It would be best if you inherit all your controllers from a custom base one in which the override is done to maintain uniformity and DRYness of the solution.
just add bellow code, before base.OnException(filterContext);
// Stop any other exception handlers from running
filterContext.ExceptionHandled = true;
I'm working on a team-project and I am in the following situation:
I created my own Exception class, and I want all the thrown exceptions of type myException to be handled and automatically redirected to the Error view where I would nicely display the error, which is ok to do. This is what I added in my Web.config:
<customErrors mode="On" defaultRedirect="Error" />
The issue is I want all the rest of the exceptions to be thrown normally, seeing all the information about it, including the stack trace, the source file and the line error, which would be really good for the team-project.
I've tried the [HandleError(ExceptionType=typeof(myException)], but it is no use.
I also tried to override the OnException function of the controller and if the exception is not myException then i would throw it again, but i still get in the Error view.
protected override void OnException(System.Web.Mvc.ExceptionContext filterContext)
{
if (filterContext.Exception.GetType() != typeof(myException)) {
throw filterContext.Exception;
}
base.OnException(filterContext);
}
Any idea which could work?
Thanks.
You may get the result you want by leaving custom errors Off (so that for all the errors you get the stack trace displayed), and redirecting the exceptions you want to the controller/view you need (so that a friendly-looking page will be displayed).
You could define a base controller for all your controllers, and override its OnException method with something like below:
if (filterContext.Exception.GetType() == typeof(YourCustomException))
{
filterContext.ExceptionHandled = true;
filterContext.Result = RedirectToAction("ActionName", "ControllerName", new { customMessage = "You may want to pass a custom error message, or any other parameters here"});
}
else
{
base.OnException(filterContext);
}
I would like to know whether or not it is possible to clear an exception out of the request when trying to hit the Render Phase after the Action Phase has thrown the exception.
If you look at this code snippet from the doRenderService method of DispatchPortlet.class (a Spring provided class):
PortletSession session = request.getPortletSession(false);
if (session != null) {
if (request.getParameter(ACTION_EXCEPTION_RENDER_PARAMETER) != null) {
Exception ex = (Exception)
session.getAttribute(ACTION_EXCEPTION_SESSION_ATTRIBUTE);
if (ex != null) {
logger.debug("Render phase found exception caught during action phase - rethrowing it");
throw ex;
}
}
else {
session.removeAttribute(ACTION_EXCEPTION_SESSION_ATTRIBUTE);
}
}
You can see here that an exception gets put into the parameter map and there doesn't seem to be any way to clear it out.
What I would like to do is originally catch the Exception (what I am successfully doing), display an "Error Page" (what I am successfully doing), then display a button on that Error Page that allows the user to bring up the "Render Phase" page again so that he/she may be able to try their Action, again.
I've tried to create a filter, interceptor, new controller to clear the parameter, but it seems that the ParameterMap is an UnmodifiableCollection.
Any thoughts?
I actually was able to figure this out by doing the following in a render-phase filter:
session.setAttribute(ACTION_EXCEPTION_SESSION_ATTRIBUTE, null)
You can configure your org.springframework.web.portlet.DispatcherPortlet with setForwardActionException(false). This prevents spring from adding the Exception details in render parameters, or session.