Exception handling in transformer - spring-integration

We are facing an issue while exception is encountered in transformer.
Below is the scenario:
We have a router and a transformer with the below configuration
<bean id="commonMapper"
class="com.example.commonMapper"></bean>
<int:router input-channel="channelA" ref="commonMapper"
method="methodA" />
<int:transformer input-channel="channel_2"
ref="commonMapper" method="methodB"
output-channel="channelC"></int:transformer>
CommonMapper.java :
public String methodA(SomeBean someBean) {
if (<some business condition example someBean.getXValue()>) {
return "channel_1";
} else if(<some condition>) {
return "channel_2"; // Assuming it enters this condition, based on this the above transformer with input-channel="channel_2" gets called
}else if (<some condition>) {
return "channel_3";
} else {
return "channel_4";
}
}
public SomeBean methodB(Message<SomeBean> message)
throws Exception{
SomeBean someBean = message.getPayload();
someBean.setY(10/0); // Purposely introducing an exception
}
While debugging the application, we found that whenever an exception is encountered in methodB(), the control goes back to router reference method i.e. methodA() and again satisfy the condition and calls the transformer (with input-channel="channel_2"). This repeats for certain iteration. And then exception is logged via AnnotationMethodHandlerExceptionResolver -> resolveException.
Below are the queries:
Why does the router gets called again when it encounters an exception in transformer?
Is it the bug or the normal behavior?
How to tackle this issue?
Please let me know if you need any more details around it.

The Spring Integration flow is just a plain Java methods chain call. So, just looks at this like you call something like: foo() -> bar() -> baz(). So, when exception happens in the last one, without any try...catch in the call stack, the control will come back to the foo() and if there is some retry logic, it is going to call the same flow again.
I'm not sure what is your AnnotationMethodHandlerExceptionResolver, but looks like your talk about this one:
Deprecated.
as of Spring 3.2, in favor of ExceptionHandlerExceptionResolver
#Deprecated
public class AnnotationMethodHandlerExceptionResolver
extends AbstractHandlerExceptionResolver
Implementation of the HandlerExceptionResolver interface that handles exceptions through the ExceptionHandler annotation.
This exception resolver is enabled by default in the DispatcherServlet.
This means that you use pretty old Spring. I don't think that it is related though, but your top of the call stack is Spring MVC. You need to take a look there what's going on with the retry.
And answering to all you question at once: yes, this is a normal behavior - see Java call explanation above. You need to debug Spring code from the IDE to figure out what is going on the MVC level

Related

How to mock EntityBus.rxSend()

The io.vertx.reactivex.core.eventbus.EventBus.rxSend() method has the following signature:
public <T> Single<Message<T>> rxSend(String address,
Object message,
DeliveryOptions options)
What is the correct way to mock this so that it returns a Single containing a real object? The issue is that the Message class has no constructor apart from one which which takes another Message object.
So the following will compile:
Mockito.when(eventBus.rxSend(Mockito.isA(String.class),
Mockito.isA(JsonObject.class),
Mockito.isA(DeliveryOptions.class))).thenReturn(Single.just(new Message<Object>(null)));
but of course Single.just(new Message<Object>(null))does not contain a real object which can then be passed on to test the next handler in the verticle.
Thanks
like i mentioned in my comment, i don't have an answer to your immediate question, but i'd instead like to recommend a different approach to getting the results you're looking for.
mocking types that you don't own is generally discouraged for a variety of reasons. the two that resonate most with me (as i've fallen victim) are:
if the real implementation of the mocked dependency changes, the mock's behavior will not automatically reveal any forward-breaking changes.
the more mocks a test introduces, the more cognitive load the test carries. and some tests require a lot of mocks in order to work.
there are lots of articles on the topic with more detailed viewpoints and opinions. if you're interested, refer to the Mockito wiki, or just Google around.
given all that, rather than mocking EventBus, why not use an actual instance and receive real reply Messages composed by the framework? sure, strictly speaking this becomes more of an integration test than a unit test, but is closer to the type of testing you want.
here's an example snippet from a test i wrote in an existing project with some added comments. (the code refers to some non-standard types with an -"Ext" suffix, but they aren't salient to the approach).
private EventBus eventBus;
#Before
public setUp(#NotNull TestContext context) {
eventBus = Vertx.vertx().eventBus()
}
#Test
public void ping_pong_reply_test(#NotNull TestContext context) {
final Async async = context.async();
// the following is a MessageConsumer registered
// with the EventBus for this specific test.
// the reference is retained so that it can be
// "unregistered()" upon completion of this test
// so as not to affect other tests.
final MessageConsumer<JsonObject> consumer = eventBus.consumer(Ping.class.getName(), message -> {
// here is where you would otherwise place
// your mock Message generation.
MessageExt.replyAsJsonObject(message, new Pong());
});
final Ping message = new Ping();
final DeliveryOptions options = null;
// the following uses an un-mocked EventBus to
// send an event and receive a real Message reply.
// created by the consumer above.
EventBusExt.rxSendJsonObject(eventBus, message, options).subscribe(
result ->
// result.body() is JSON that conforms to
// the Pong type
consumer.unregister();
async.complete();
},
error -> {
context.fail(error);
}
);
}
i hope this at least inspires some new thinking around your problem.

No annotated method found, falling back to SequenceSizeReleaseStrategy

I tried to create a single bean which combined the release strategy method and the aggregator method:
public class POJOSingleAggregatorStrategy{
#Aggregator
public Message spliceMessage(List<Message<?>> messages) {
...
}
#ReleaseStrategy
public boolean canRelease(MessageGroup messageGroup) {
...
}
}
<channel id="inputChannel"/>
<channel id="outputChannel"/>
<bean id="aggregatorStrategyBean" class="sample.POJOSingleAggregatorStrategy"/>
<aggregator id="completelyDefinedAggregator" input-channel="inputChannel" output-channel="outputChannel" send-partial-result-on-expiry="false" ref="aggregatorStrategyBean" method="spliceMessage"/>
Without config release-strategy-method, the program works well but it repors a warning:
No annotated method found; falling back to SequenceSizeReleaseStrategy, target:sample.POJOSingleAggregatorStrategy, methodName:null
After configured release-strategy-method="canRelease", the program doesn't work and it reports an exception: java.lang.IllegalStateException: Failed to process message list
Anybody knows how to avoid this warning? (Except for rewrite ReleaseStrategyFactoryBean)
Strange indeed; we have a test case here and here that does the same thing and it works fine.
If you can post a simple test case that reproduces the issue, we can take a look.
You also need to provide the full stack trace for the IllegalStateException.

Rendering GORM classes from Spring Boot

I'm trying to write a simple Spring Boot controller that renders a GORM instance and failing.
Here's a shortened version of my code:
#RestController
#RequestMapping("/user")
class UserController {
#RequestMapping(value='/test', method=GET)
User test() {
return new User(username: 'my test username')
}
}
I get the following error message:
Could not write JSON: No serializer found for class org.springframework.validation.DefaultMessageCodesResolver and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: users.domain.User["errors"]->grails.validation.ValidationErrors["messageCodesResolver"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class org.springframework.validation.DefaultMessageCodesResolver and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: users.domain.User["errors"]->grails.validation.ValidationErrors["messageCodesResolver"])
The error seems to be caused by extra properties injected by GORM. What is the proposed solution for this? Will this eventually be solved in gorm-hibernate4-spring-boot? Should I simply disable SerializationFeature.FAIL_ON_EMPTY_BEANS (I don't have a lot of experience with Jackson so I'm not entirely sure what side effects this may have)? Should I use Jackson's annotations to solve the problem? Any other options?
I've found a way to get rid of the error using this code:
#Component
class ObjectMapperConfiguration implements InitializingBean {
#Autowired
ObjectMapper objectMapper
#Override
void afterPropertiesSet() {
def validationErrorsModule = new SimpleModule()
validationErrorsModule.addSerializer(ValidationErrors, new ErrorsSerializer())
objectMapper.registerModule(validationErrorsModule)
}
}
class ErrorsSerializer extends JsonSerializer<ValidationErrors> {
#Override
void serialize(ValidationErrors errors, JsonGenerator jgen, SerializerProvider provider) {
jgen.writeStartObject()
jgen.writeEndObject()
}
}
Obviously this solution is far from perfect as it simply nukes all validation errors but right now it is good enough for me. I am pretty sure the Spring Boot team will have to address this issue eventually as the GORM objects are also being serialized with some internal Hibernate properties like attached. I'm not accepting this answer as it is not an acceptable solution for most scenarios, it basically just squelches the exception.
This did not work for me.
So I used this instead and the error disappeared.
#JsonIgnoreProperties(["errors"])
I'm using springBootVersion '1.4.1.RELEASE' with gorm & hibernate5:
compile("org.grails:gorm-hibernate5-spring-boot:6.0.3.RELEASE")
I am having to include the following at the top of each domain class in order to use them in a client response (i.e. json serialization using jackson):
#JsonIgnoreProperties(["errors", "metaClass", "dirty", "attached", "dirtyPropertyNames"])
When using springBootVersion '1.3.5.RELEASE' I was able to get away with:
#JsonIgnoreProperties(["errors"])
This is trending in the wrong direction :)

Logging Exception using Aspect Oriented Programming

I want to log exception for all of my methods using AOP. I had created an attribute for the same as following:
[AttributeUsage(AttributeTargets.All)]
public class ClsLogger : System.Attribute
{
private string _exMsg;
public ClsLogger(string exMsg)
{
//
// TODO: Add constructor logic here
//
_exMsg = exMsg;
LogError();
}
public void LogError()
{
// This methods logs exception
// Log Exception
}
}
Finally, I want to use this logging attribute to log exception messages of the methods of my application. How I can pass exception messages to the atrribute as it is not a fixed string but varrible?
Could anybody help on this?
Attributes in C# don't instantiate until you call GetCustomAttributes, and they instantiate every time you do so (see this question here on SO).
If you want to use AOP (as your title indicates), then you'll need to use some framework, like PostSharp, Fody, SheepAspect, etc.
If you are using ASP.NET MVC, then there is a built-in ActionFilter class that you can also use, but only on Controller methods.

NInject and thread-safety

I am having problems with the following class in a multi-threaded environment:
public class Foo
{
[Inject]
public IBar InjectedBar { get; set; }
public bool NonInjectedProp { get; set; }
public void DoSomething()
{
/* The following line is causing a null-reference exception */
InjectedBar.DoSomething();
}
public Foo(bool nonInjectedProp)
{
/* This line should inject the InjectedBar property */
KernelContainer.Inject(this);
NonInjectedProp = nonInjectedProp;
}
}
This is a legacy class which is why I am using property rather than constructor injection.
Sometime when the DoSomething() is called the InjectedBar property is null. In a single-threaded application, everything runs fine.
How can this be occuring and how can I prevent it?
I am using NInject 2.0 without any extensions, although I have copied the KernelContainer from the NInject.Web project.
I have noticed a similar problem occurring in my web services. This problem is extremely intermittent and difficult to replicate.
First of all, let me say that this is wrong on so many levels; the KernelContainer was an infrastructure class kept specifically to work around certain limitations in the ASP.NET WebForms page lifecycle. It was never meant to be used in application code. Using the Ninject kernel (or any DI container) as a service locator is an anti-pattern.
That being said, Ninject itself is definitely thread-safe because it's used to service parallel requests in ASP.NET all the time. Wherever this NullReferenceException is coming from, it's got little if anything to do with Ninject.
I can think of two possibilities:
You have to initialize KernelContainer.Kernel somewhere, and that code might have a race condition. If something tries to use the KernelContainer before the kernel is fully initialized (possible if you use the IKernel.Bind methods instead of loading modules as per the guidance), you'll get errors like this. Or:
It's your IBar implementation itself that has problems, and the NullReferenceException is happening somewhere inside the DoSomething method. You don't actually specify that InjectedBar is null when you get the exception, so that's a legitimate possibility here.
Just to narrow the field of possibilities, I'd eliminate the KernelContainer first. If you absolutely must use Ninject as a service locator due to a poorly-designed legacy architecture, then at least allow it to create the dependencies instead of relying on Inject(this). That is to say, whichever class or classes need to create your Foo, have that class call kernel.Get<Foo>(), and set up your kernel to Bind<Foo>().ToSelf().

Resources