Drools get object from map mvel cast exception - drools

I am using jboss EAP 7.2 and Red Hat Decision Central 7.5.0
I have a custom objects like that
public class Model{
private String id;
private Map<String, Object> map;
// ... getters and setters
}
public class ParameterModel{
private String parameterName;
private BigDecimal maxValue;
private BigDecimal minValue;
private Object value;
// ... getters and setters
}
I have created new "Model" object that has custom "id" attribute and "map" attribute contains <parameterName, ParameterModel> pairs.
I sent it to decision manager and drools side ı want to achieve ParameterModel attributes but I could not.
My rule is below.
package com.rule.test;
import com.test.Model;
import com.test.ParameterModel;
rule "drools1"
when
Model(getId().equals("1"), Integer.parseInt(((ParameterModel)getMap().get("param1")).getValue().toString())>10)
then
System.out.println("Error on " + drools.getRule().getName());
end
The exception is below.
Caused by: [Error: null pointer:
Integer.parseInt(((ParameterModel)getMap().get("param1")).getValue().toString())]
[Near : {... Integer.parseInt(((ParameterMo ....}] In [Rule "drools1"
in com/rule/test/test.drl]
Caused by: java.lang.NullPointerException
at org.mvel2.DataConversion.convert(DataConversion.java:129)
at org.mvel2.ast.TypeCast.getReducedValueAccelerated(TypeCast.java:74)
at org.mvel2.compiler.ExecutableAccessor.getValue(ExecutableAccessor.java:38)
at org.mvel2.ast.Substatement.getReducedValueAccelerated(Substatement.java:44)
at org.mvel2.ast.Union.getReducedValueAccelerated(Union.java:44)
at org.mvel2.compiler.ExecutableAccessor.getValue(ExecutableAccessor.java:38)
at org.mvel2.optimizers.impl.refl.ReflectiveAccessorOptimizer.getMethod(ReflectiveAccessorOptimizer.java:970)
at org.mvel2.optimizers.impl.refl.ReflectiveAccessorOptimizer.compileGetChain(ReflectiveAccessorOptimizer.java:396)
Thank you all.

Drools has a lot of built-in null checking, but if you insist on bypassing it you're going to end up with a lot of errors.
The other kind of interesting Drools has is a special syntax for maps -- get("foo") can be written as this["foo"].
rule "drools1"
when
Model( id == "1", // equivalent to getId().equals("1")
$map: map != null )
// Special syntax for getting stuff from maps:
Map( $param1: this["param1"] != null ) from $map
ParameterModel( $value: value != null ) from $param1
Integer( this > 10 ) from Integer.parseInt($value.toString())
then
System.out.println("Error on " + drools.getRule().getName());
end
Why was your version giving a NPE? Not a clue, but it was also just about unreadable in its original form. All that really can be gleaned from the stack trace was that it was occurring at some implicit conversion step.
Of course this version will also fail if value isn't something whose toString() turns into a String representation of an integer.
Note that if value is actually an Integer type, then you don't need to waste time with the parse int and can just do:
Integer(this > 10) from $value

Related

JPQL Query - No constructor taking error?

I have a Card entity class with many columns.
I used dto because I want to get some columns from this Entity.
I created a DTO class and wrote a query to CardRepositoryCustom.
But when I try to run the Query I get various errors "No constructor taking".
My dto class:
#Data
#NoArgsConstructor
#AllArgsConstructor
public class CardDTO {
private String test1;
private String test2;
private String test3;
private String test4;
}
JPQL RepositoryCustom :
#Repository
#Transactional
public class CardRepositoryCustom {
public CardDTO test1() {
JpaResultMapper jpaResultMapper = new JpaResultMapper();
String q = "SELECT "+
" c.test1 "+
"FROM "+
" CardEntity c ";
Query query = entityManager.createQuery(q);
try {
return jpaResultMapper.uniqueResult(query, CardDTO.class);
} catch (NoResultException nre) {
return null;
}
}
}
Errors:
java.lang.RuntimeException: No constructor taking: java.lang.String
at org.qlrm.mapper.JpaResultMapper.findConstructor(JpaResultMapper.java:107) ~[qlrm-1.7.1.jar:na]
at org.qlrm.mapper.JpaResultMapper.uniqueResult(JpaResultMapper.java:64) ~[qlrm-1.7.1.jar:na]
at ....
I know how to fix this error.
You just need to write the following constructor in the DTO class as shown below.
public CardDTO(String test1) {
this.setTest1(test1);
}
Here I am curious, if I want test2, test3, test4 and write Query in Custom class, should there be as many constructors in DTO class as that number?
I think this method is really inefficient. Is there any solution I am not aware of?
This seems to be more about QLRM than JPA or Spring.
Judging from the error message the constructor has to match the arguments provided. Probably the easiest variant is to always provide all arguments, possibly with a value of null or some other literal.
The query in your example would then become.
SELECT c.test1, null, null, null FROM CardEntity c
Of course QLRM just provides a JpaResultMapper and it would probably not too difficult to provide your own, or offer a PR to QLRM that inspects names of the result set and tries to match them to parameter names or the constructor.

JSON parse error: Unrecognized field MongoDB Spring Boot

I am trying to save the following Java object as a document in MongoDB, here are my classes:
public class GenericIpConfig {
String connection_type;
String port;
String port_ingenico;
String ip;
String ip_ingenico;
String id_ingenico;
boolean active_ingenico;
long lastPushTime;
}
#Data
#Document(collection = "generic_device_config")
public class GenericDeviceConfig {
#Id
String _id;
String storeCode;
String companyCode;
long updated;
boolean enabled;
ArrayList<SerialPort> serialPorts;
String companyId;
GenericIpConfig ipConfig;
}
And this is the request I am sending with POSTMAN:
{
"updated":0,
"enabled":true,
"serialPorts":[],
"companyId":"600",
"companyCode":"0",
"storeCode":"0",
"ipConfig": {
"connection_type":"ETHERNET",
"port": "23",
"port_ingenico": "",
"ip": "192.168.10.55",
"ip_ingenico": "",
"id_ingenico": "",
"active_ingenico": false,
"lastPushTime": 0
}
}
For some reason, I keep getting the following error:
JSON parse error: Unrecognized field \"connection_type\" (class it.igesa.monitoringsystem.model.mongo.device.config.GenericIpConfig), not marked as ignorable; nested exception is com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field \"connection_type\" (class it.igesa.monitoringsystem.model.mongo.device.config.GenericIpConfig), not marked as ignorable (0 known properties: ]
I feel like my code is missing something, since this is the first time I am working with SpringBoot/MongoDB;
It looks as if Jackson can't recognise setter methods for fields, because they don't follow java naming conventions. Try fixing the unrecognised fields with this annotation - #JsonProperty("property_name_here"), by putting it on the setters.
You are also mixing them, some of your fields are named something_something, while others are somethingSomething, which is the standard java way. It's a good idea to pick one and stick to it for the project.
You should also read up on serialization with jackson documentation, annotation examples.
Finally I found the solution. Defining setters and getters annotations for the nested class solved the problem.
I had an extra getter method in a class that I was reusing.
It worked fine when I removed the extra getter.
I hope you find this useful too.
Thanks a lot.

How to add element to array with Drools (mvel)

I need insert a new value in a exist array with Drools. My example:
rule "insert new address"
dialect "java"
when
$data : Data( source.address != null)
then
Address address = (Address) $data.source.address
System.out.println("Element: "+address );
$data.target.addressList.add(address);
end
The error that happend is this:
Exception executing consequence for rule "insert new address" in rules: [Error: $data.target.addressList.add(address): null]
EDIT: Added the model
public class Data {
private Source source;
private Client target;
}
public class Source {
...
private Address address;
}
public class Client {
...
private List<Address> addressList;
}
In answer to the question in your title, which is how to add an element to array -- the answer is basically "the same way you would in Java."
To answer the question you actually asked, which has no arrays, your error is effectively a NullPointerException, or another indicator that the field cannot be modified (eg an immutable list.)
This:
Error: $data.target.addressList.add(address): null]
Means that either $data.target or $data.target.addressList is null, or possibly $data.target.addressList is an immutable list.
Make sure that whatever "target" is has been initialized, and that its "addressList" is also initialized as a mutable list type.

Date format changed in Payara 5 (Long does not work anymore ) -- org.eclipse.yasson.YassonProperties#ZERO_TIME_PARSE_DEFAULTING

Using Payara 4.174 and receive in backend the date as a long, for example 1540545780000. Now, I upgraded to Payara version 5.
public User {
String name;
Date birthdate;
}
#POST
#Path("/user/)
public void createUser(User user) {
...
}
json call
{
name: "name",
birthdate: 1540545780000
}
Now The call brakes with the following error:
Caused by: javax.json.bind.JsonbException: Error parsing class java.util.Date from value: 1540545780000. Check your #JsonbDateFormat has all time units for class java.util.Date type, or consider using org.eclipse.yasson.YassonProperties#ZERO_TIME_PARSE_DEFAULTING.
at org.eclipse.yasson.internal.serializer.AbstractDateTimeDeserializer.deserialize(AbstractDateTimeDeserializer.java:70)
at org.eclipse.yasson.internal.serializer.AbstractContainerDeserializer.deserializeInternal(AbstractContainerDeserializer.java:85)
at org.eclipse.yasson.internal.serializer.AbstractContainerDeserializer.deserialize(AbstractContainerDeserializer.java:61)
at org.eclipse.yasson.internal.Unmarshaller.deserializeItem(Unmarshaller.java:62)
at org.eclipse.yasson.internal.Unmarshaller.deserialize(Unmarshaller.java:52)
at org.eclipse.yasson.internal.JsonBinding.deserialize(JsonBinding.java:45)
at org.eclipse.yasson.internal.JsonBinding.fromJson(JsonBinding.java:85)
at org.glassfish.jersey.jsonb.internal.JsonBindingProvider.readFrom(JsonBindingProvider.java:99)
... 62 common frames omitted
Caused by: java.time.format.DateTimeParseException: Text '1540545780000' could not be parsed at index 0
Jonathan is partly right. You don't have to write a custom DateTypeDeserializer to solve your issue. However, as the error message describes, you can annotate your Field with #JsonbDateFormat to resolve your error, you have to make sure it has all time units.
Here is an example:
public User {
String name;
#JsonbDateFormat(value = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX")
Date birthdate;
}
This is because Payara 5 switched to using Yasson as its JsonB provider, which does not contain a mapper for long to java.util.Date (see here). You have to write your own version to map a number to Date format.

spring cloud stream kafka 2.0 - StreamListener with condition

I'm trying to create a consumer using StreamListener annotation and condition attirbute.However , i'm getting the following exception :
org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.lang.Integer] for value 'test'; nested exception is java.lang.NumberFormatException: For input string: "test"
TestListener:
#StreamListener(target=ITestSink.CHANNEL_NAME,condition="payload['test'] == 'test'")
public void test(#Payload TestObj message) {
log.info("message is {}",message.getName());
}
TestObj:
#Data
#ToString(callSuper=true)
public class TestObj {
#JsonProperty("test")
private String test;
#JsonProperty("name")
private String name;
}
can someone assist with this issue?
the payload of the message is not yet converted from the wire format (byte[]) to the desired type. In other words, it has not yet gone through the type conversion process described in the Content Type Negotiation.
So, unless you use a SPeL expression that evaluates raw data (for example, the value of the first byte in the byte array), use message header-based expressions (such as condition = "headers['type']=='dog'").
Example:
#StreamListener(target = Sink.INPUT, condition = "headers['type']=='bogey'")
public void receiveBogey(#Payload BogeyPojo bogeyPojo) {
// handle the message
}
Check the Spring documentation here.
From what you show, it should work. I suggest you remove the condition, then set breakpoint to debug. Then you should be able to know which actual type is.