How to print only constraint message from BeanValidationException - apache-camel

I want to print only constraint message but apachecamel printing complete message like
Bean Code part
#NotNull(message="Validation Error name value Missing.")
private String name;
Router Code
onException(BeanValidationException.class)
.handled(true)
.process( new FailedResponseProcessor() );
Processor code
public void process(Exchange exchange) throws Exception {
Exception e = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class);
Response response = new Response();
response.setRequestStatus("Failed");
response.setRequestMessage(e.getMessage());
Following is response received
<response>
<requestStatus>Failed</requestStatus>
<requestMessage>Validation failed for: org.my.Request#1b8a0be3 errors: [property: name; value: null; constraint: Validation Error name value Missing.; ]. Exchange[ID-WCB00073679-49595-1507251546181-0-1]</requestMessage>
</response>

Below works for me
BeanValidationException bve = (BeanValidationException) exchange.getProperty(Exchange.EXCEPTION_CAUGHT);
Set<ConstraintViolation<Object>> constraintViolations = bve.getConstraintViolations();
ConstraintViolation<Object> constraintViolation = constraintViolations.iterator().next();
System.out.println( constraintViolation.getMessage() );

Related

What is significance getDml code below in Salesforce Test code

Can anyone explain me significance getDml code below in Salesforce Test code
#isTest static void TestContactWithInvalidNameNotInserted(){
String inputLastName = 'INVALIDNAME';
Contact newcontact = new Contact(LastName=inputLastName);
Test.startTest();
try{
insert newcontact;
}
catch(DmlException dmlEx){
String expectedMessage = 'The Last Name' +newcontact.LastName+'is not allowed for DML';
System.assertEquals(expectedMessage, dmlEx.getDmlMessage(0));
}
Test.stopTest();
}
}
In this instance the catch block only catches exceptions of type DmlException. getDmlMessage() is how you can get the message property of the exception.
Thanks,
Matt

How to handle exception while parsing JSON in Flink

I am reading data from Kafka using flink 1.4.2 and parsing them to ObjectNode using JSONDeserializationSchema. If the incoming record is not a valid JSON then my Flink job fails. I would like to skip the broken record instead of failing the job.
FlinkKafkaConsumer010<ObjectNode> kafkaConsumer =
new FlinkKafkaConsumer010<>(TOPIC, new JSONDeserializationSchema(), consumerProperties);
DataStream<ObjectNode> messageStream = env.addSource(kafkaConsumer);
messageStream.print();
I am getting the following exception if the data in Kafka is not a valid JSON.
Job execution switched to status FAILING.
org.apache.flink.shaded.jackson2.com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'This': was expecting ('true', 'false' or 'null')
at [Source: [B#4f522623; line: 1, column: 6]
Job execution switched to status FAILED.
Exception in thread "main" org.apache.flink.runtime.client.JobExecutionException: Job execution failed.
The easiest solution is to implement your own DeserializationSchema and wrap JSONDeserializationSchema. You can then catch the exception and either ignore it or perform custom action.
As suggested by #twalthr, I implemented my own DeserializationSchema by copying JSONDeserializationSchema and added exception handling.
import org.apache.flink.api.common.serialization.AbstractDeserializationSchema;
import org.apache.flink.shaded.jackson2.com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.flink.shaded.jackson2.com.fasterxml.jackson.databind.node.ObjectNode;
import java.io.IOException;
public class CustomJSONDeserializationSchema extends AbstractDeserializationSchema<ObjectNode> {
private ObjectMapper mapper;
#Override
public ObjectNode deserialize(byte[] message) throws IOException {
if (mapper == null) {
mapper = new ObjectMapper();
}
ObjectNode objectNode;
try {
objectNode = mapper.readValue(message, ObjectNode.class);
} catch (Exception e) {
ObjectMapper errorMapper = new ObjectMapper();
ObjectNode errorObjectNode = errorMapper.createObjectNode();
errorObjectNode.put("jsonParseError", new String(message));
objectNode = errorObjectNode;
}
return objectNode;
}
#Override
public boolean isEndOfStream(ObjectNode nextElement) {
return false;
}
}
In my streaming job.
messageStream
.filter((event) -> {
if(event.has("jsonParseError")) {
LOG.warn("JsonParseException was handled: " + event.get("jsonParseError").asText());
return false;
}
return true;
}).print();
Flink has improved null record handling for FlinkKafkaConsumer
There are two possible design choices when the DeserializationSchema encounters a corrupted message. It can either throw an IOException which causes the pipeline to be restarted, or it can return null where the Flink Kafka consumer will silently skip the corrupted message.
For more details, you can see this link.

Indexing with simple expression broken in Apache Camel 2.18

The following sample code works fine with all versions of Camel, excluding 2.18.x
from("direct:process")
.process(new Processor() {
public void process(Exchange exchange) {
List<String> alist = new ArrayList<String>();
alist.add("1");
alist.add("99");
exchange.getIn().setHeader("ITEMS", alist);
exchange.getIn().setHeader("TOTAL_LOOPS", alist.size());
}
})
.loop(simple("${header.TOTAL_LOOPS}", Integer.class))
.setHeader("item", simple("${header.ITEMS[${property.CamelLoopIndex}]}", String.class))
.log(LoggingLevel.INFO, LOG_CLASS_NAME, simple("item = ${header.item} and TOTAL_MAPS = ${header.TOTAL_LOOPS}").getText())
.end()
.end();
However with 2.18.x, the following exception gets thrown:
2017-02-03 21:13:31 ERROR DefaultErrorHandler:204 - Failed delivery
for (MessageId: ID-CATL0W10D4DG4R1-55822-1486174410756-0-1 on
ExchangeId: ID-CATL0W10D4DG4R1-55822-1486174410756-0-2). Exhausted
after delivery attempt: 1 caught:
org.apache.camel.language.bean.RuntimeBeanExpressionException: Failed
to invoke method: [${property.CamelLoopIndex}] on java.util.ArrayList
due to: java.lang.IndexOutOfBoundsException: Key:
${property.CamelLoopIndex} not found in bean: [1, 99] of type:
java.util.ArrayList using OGNL path [[${property.CamelLoopIndex}]]

SimpleBuilder usage in camel

I have following processor, when I run it from my route I get the following error. I know exchange body is not null and you can see it in logs below. What is wrong with my usage of SimpleBuilder here ?
public class UpdateCustomerProcessor implements Processor {
public static final Logger log = LoggerFactory.getLogger(UpdateCustomerProcessor.class);
public void process(Exchange exchng) throws Exception {
Customer c = (Customer) exchng.getIn().getBody(Object[].class)[0];
System.out.println("Updating customer " + c.getFirstName() + " " + c.getLastName());
System.out.println(SimpleBuilder.simple("Hello ${body.getFirstName()}").evaluate(exchng, String.class));
exchng.getOut().setBody(new Object[] {});
}
}
log->Updating customer aaa bbb
error-> org.apache.cxf.interceptor.Fault: Failed to invoke method: .getFirstName() on null due to: org.apache.camel.language.bean.RuntimeBeanExpressionException: Failed to invoke method: getFirstName() on null
I can't make sense of the "null"-exception, since exchange in appears to be filled. Nevertheless, your expression looks incorrect - since your exchange.in seems to hold an array, it should be:
SimpleBuilder.simple("Hello ${body[0].firstname}").evaluate(exchng, String.class))

Setting a header based on an XQuery filter

I have a route that's set to run in batched mode, polling several thousand XML files. Each is timestamped inside the XML structure and this dateTime element is used to determine whether the XML should be included in the batch's further processing (an XQuery transform). As this is a batch route it self-terminates after execution.
Because the route needs to close itself I have to ensure that it also closes if every message is filtered out, which is why I don't use a filter but a .choice() statement instead and set a custom header on the exchange which is later used in a bean that groups matches and prepares a single source document for the XQuery.
However, my current approach requires a second route that both branches of the .choice() forward to. This is necessary because I can't seem to force both paths to simply continue. So my question is: how can get rid of this second route? One approach is setting the filter header in a bean instead but I'm worried about the overhead involved. I assume the XQuery filter inside Camel would greatly outperform a POJO that builds an XML document from a string and runs an XQuery against it.
from(sourcePath + "?noop=true" + "&include=.*.xml")
.choice()
.when()
.xquery("[XQuery Filter]")
.setHeader("Filtered", constant(false))
.to("direct:continue")
.otherwise()
.setHeader("Filtered", constant(true))
.to("direct:continue")
.end();
from("direct:continue")
.routeId(forwarderRouteID)
.aggregate(aggregationExpression)
.completionFromBatchConsumer()
.completionTimeout(DEF_COMPLETION_TIMEOUT)
.groupExchanges()
.bean(new FastQueryMerger(), "group")
.to("xquery:" + xqueryPath)
.bean(new FileModifier(interval), "setFileName")
.to(targetPath)
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
new RouteTerminator(routeID, exchange.getContext()).start();
new RouteTerminator(forwarderRouteID, exchange.getContext()).start();
}
})
.end();
Wouldn't .end() help here?
I mean the following:
from(sourcePath + "?noop=true" + "&include=.*.xml")
.choice()
.when()
.xquery("[XQuery Filter]")
.setHeader("Filtered", constant(false)).end()
.otherwise()
.setHeader("Filtered", constant(true)).end()
.aggregate(aggregationExpression)
.completionFromBatchConsumer()
.completionTimeout(DEF_COMPLETION_TIMEOUT)
.groupExchanges()
.bean(new FastQueryMerger(), "group")
.to("xquery:" + xqueryPath)
.bean(new FileModifier(interval), "setFileName")
.to(targetPath)
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
new RouteTerminator(routeID, exchange.getContext()).start();
new RouteTerminator(forwarderRouteID, exchange.getContext()).start();
}
});
just quickly tested the following one and it worked:
#Produce(uri = "direct:test")
protected ProducerTemplate testProducer;
#EndpointInject(uri = "mock:test-first")
protected MockEndpoint testFirst;
#EndpointInject(uri = "mock:test-therest")
protected MockEndpoint testTheRest;
#EndpointInject(uri = "mock:test-check")
protected MockEndpoint testCheck;
#Test
public void test() {
final String first = "first";
final String second = "second";
testFirst.setExpectedMessageCount(1);
testTheRest.setExpectedMessageCount(1);
testCheck.setExpectedMessageCount(2);
testProducer.sendBody(first);
testProducer.sendBody(second);
try {
testFirst.assertIsSatisfied();
testTheRest.assertIsSatisfied();
testCheck.assertIsSatisfied();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Override
protected RouteBuilder createRouteBuilder() {
return new RouteBuilder() {
public void configure() {
from("direct:test")
.choice()
.when(body().isEqualTo("first")).to("mock:test-first")
.otherwise().to("mock:test-therest").end()
.to("mock:test-check");
}
};
}

Resources