Grails Date is being accepted as String - grails

In my grails domain I am having a field Date i.e. java.util.Date.
In my controller I am loading this date from params using SimpleDateFormate.
To be precise assume that params.date is something like '20/02/2013 02:30 am'. In the controller I load this as follows:
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm a");
domainInstance.date = simpleDateFormat.parse(params.date)
While this statement executes no error is detected. However when the domain Instance is being saved error is generated that
[typeMismatch.Domain.date,typeMismatch.date,typeMismatch.java.util.Date,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes
[Failed to convert property value of type 'java.lang.String' to required type 'java.util.Date' for property 'date'; nested exception is java.lang.IllegalArgumentException: Could not parse date: Unparseable date: "20/02/2013 02:30 am"]
Can you anyone tell me where things are going wrong.
I am pretty sure that SimpleDateFormat parses String to Date. Why is it accepting as String.

Thanks for the response, but I have found the solution to the problem. The problem was something like this.
I was instantiating my domainInstance as domainInstance = new Domain(params)
This was the first statement in the controller action.
When this statement is executed params holds the date in the format "dd/MM/yyyy HH:mm a". Hence this statement adds an error in the domainInstance object.
Later after using SimpleDateFormat the variable is updated but the error still remains in the object because of which the error crops up.
The solution to this error is immediately after the statement 'domainInstance = new Domain(params)' call the statement domainInstance.clearErrors().
This clears up all the errors in the object. Later when the domainInstance is being saved validate is called. In case validate fails due to some other error then the respective error is added at that time.
Rammohan

Grails 2.3.1 is actual problem
def domain = new FooBar(params)
domain.clearErrors()
domain.save(flush:true) // <--- validation will be there
if (doamin.hasErrors()) {
... do something
}

You can try:
domainInstance.date = new Date().parse("dd/MM/yyyy HH:mm a", params.date)

Related

failure in serializing optional date type filed to avro regardless of null value or non-null value

We are using avro1.8.2 to serialize data with optional date type field to be published to topic.
record aRecord {
/** Variable: lastUpdate
* lastUpdate indicates the latest date and time the reference asset was updated
*/
union {null, date} lastUpdate = null;
/** Variable: businessDate
* businessDate indicates the business date of the reference asset price
*/
union {null, date} businessDate = null;
}
Ran into the following exception while using the avro tool generated java class to serialize the data:
Error serializing avro message
Caused by: org.apache.avro.AvroRunTimeException: Unknown datum type org.joda.time.LocalDate: 2021-09-17
at org.apache.avro.generic.GenericData.getSchemaName(GenericData.java:772)
at org.apache.avro.specific.SpecificData.getSchemaName(SpecificData.java:302)
at org.apache.avro.generic.GenericData.resolveUnion
Please note that2 this happens regardless of the value is null or non-null (as shown value 2021-09-17 also caused the exception)
We did the following investigation and experiment but could not figure it out why:
Making the date field mandatory, the issue is resolved.
This is because DATE_CONVERSION is added to the corresponding field in the java class generated by avro tool.
If this field is defined as optional and default value is null, DATA_CONVERSION is not added to the java file generated by avro tool.
Using avro 1.9.1 resolved the issue unfortunately we must use avro 1.8.2
We also tried a few other versions of kafka-avro-serializer and spring-boot kafka framework. Nothing works for us.
Other projects that depend on avro1.8.2 seems to be able to handle this and we checked all the places as far as we considered relevant
and all the codes are the same except that somehow they have DATE_CONVERSION in place in the java file
generated by avro tool (although they are defined in advl file exactly the same).
Debuggin into the GenericData.java we found that if DATE_CONVERSION is in place for optional date field, getSchemaName is not called at all.
The getSchemaName basically checks of the type of the object, whether it's an Int, Record, String,...etc.
The date is a logicaltype of joda. Its real type is int as far as we understand
So our questions are:
How to make avro tool enable DATE_CONVERSION for optional "date" type field using avro 1.8.2?
If DATE_CONVERSION is not the key to resolve the issue, what's the best practice to serialize date type field using avro 1.8.2?
and this field could be null (default) or non-null.
Thanks.
SpecificData specificData = SpecificData.get();
specificData.addLogicalTypeConversion(new DateConversion());
DatumWriter<MessageClass> dw = new SpecificDatumWriter<MessageClass>(message.getSchema(), specificData);
DataFileWriter<MessageClass> dfw = new DataFileWriter<MessageClass>(dw);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
dfw.create(message.getSchema(), outputStream);
dfw.append(message);
dfw.close();
ProducerRecord<String, byte[]> record = new ProducerRecord<>(topic, key, outputStream.toByteArray());
return kafkaProducer.send(record, new Callback());
The above code fixed the issue. MessageClass is the java code generated by avro tool.
message is wrapped in specificData which is constructed with new DateConversion()
DATE_CONVERSION is exactly what is needed for optional date field during serialization.
Note that this solution is only needed as a workaround to avro1.8.

Grail: Error handling in #BindUsing

I have tried to use #BindUsing for a property (amt100) of a domain class (TcTransaction). The purpose is to convert a display format to a database format. Out of a dozen variants, here is one:
#BindUsing({tcTransaction, source ->
def result = tcTransaction.amt100
def amt = Amount100.of(source['amt100']) //parse and convert input
if (amt) {
result = amt.cents
} else {
tcTransaction.errors.rejectValue('amt100', 'tcTransaction.invalid.amount')
}
return result
})
Integer amt100
It works beautifully in the absence of errors. The problem is error management. This particular version returns the original value if the new value is invalid. It also adds an error to the domain object.
It seems adding to errors has no effect. The user is not warned.
I also tried to throw an exception. It seems whatever exception you throw you end up with a standard error code saying that the property must not be left empty. A previous post indicated this behaviour. (It has gone unanswered for two years.) I'm on Grails 3.2.8.
So, is there any theory of error management in #BindUsing? It's such a nifty mechanism.

Persisting date and nested with JSON

I'm trying to save nested person, which is json array and complains about requiring a Set.
Another problem I encountered, is that another field date cannot be null, but contains value already.
What I need to do before for adding params into my object or I have to change my json is built? I'm trying to save json post like this:
// relationship of Test
//static hasMany = [people: Person, samples: Sample]
def jsonParams= JSON.parse(request.JSON.toString())
def testInstance= new Test(jsonParams)
//Error requiring a Set
[Failed to convert property value of type 'org.codehaus.groovy.grails.web.json.JSONArray' to required type 'java.util.Set' for property 'people'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [com.Person] for property 'people[0]': no matching editors or conversion strategy found]]
//error saying its null
Field error in object 'com.Test' on field 'samples[2].dateTime': rejected value [null]; codes [com.Sample]
//...
"samples[0].dateTime_hour":"0",
"samples[0].dateTime_minute":"0",
"samples[0].dateTime_day":"1",
"samples[0].dateTime_month":"0",
"samples[0].dateTime_year":"-1899",
"samples[0]":{
"dateTime_minute":"0",
"dateTime_day":"1",
"dateTime_year":"-1899",
"dateTime_hour":"0",
"dateTime_month":"0"
},
"people":[
"1137",
"1141"
], //...
First off, ths line is unnecessary:
def jsonParams= JSON.parse(request.JSON.toString())
The request.JSON can be directly passed to the Test constructor:
def testInstance = new Test(request.JSON)
I'm not sure what your Person class looks like, but I'm assuming those numbers (1137, 1141) are ids. If that is the case, then your json should work - there's a chance that passing the request.JSON directly could help. I tested your JSON locally and it has no problem associating the hasMany collection. I also used:
// JSON numbers rather than strings
"people": [1137, 1141]
// using Person map with the id
"people: [{
"id": 1137
}, {
"id": 1141
}]
Both of these worked as well and are worth trying.
Concerning the null dateTime, I would rework your JSON. I would send the dateTime in a single field, instead of splitting the value into hour/minute/day/etc. The default formats are yyyy-MM-dd HH:mm:ss.S and yyyy-MM-dd'T'hh:mm:ss'Z', but these can be defined by the grails.databinding.dateFormats config setting (config.groovy). There are other ways to do the binding as well (#BindingFormat annotation) but it's going to be easiest to just send the date in a way that grails can handle without additional configuration.
If you are dead set on splitting the dateTime into pieces, then you could use the #BindUsing annotation:
class Sample{
#BindUsing({obj, source ->
def hour = source['dateTime_hour']
def minute = source['dateTime_minute']
...
// set obj.dateTime based on these pieces
})
Date dateTime
}
An additional comment on your JSON, you seem to have samples[0] defined twice and are using 2 syntaxes for your internal collections (JSON arrays and indexed keys). I personally would stick with a single syntax to clean it up:
"samples": [
{"dateTime": "1988-01-01..."}
{"dateTime": "2015-10-21..."}
],"people": [
{"id": "1137"},
{"id": "1141"}
],

getting error updating the sqlite

I am doing the project and I am structed in database path. I am using the sqlite database for storing. In this my problems is when I updating the table it showing the error. For database part I am using prewritten classes. I am calling that class method whenever I need. See below you can understand.
This below code is working fine
[DataCachingHelper updateTable:#"sendertable" data:dic3 where:#"MESSAGE_ID='1234'"];
but when I am sending the object to the "where", It showing some error.
[DataCachingHelper updateTable:#"sendertable" data:dic3 where:#"MESSAGE_ID=%#",#"hai"];
i am getting the error:
"too many arguments to methods call expected 3,have 4".
here MESSAGE_ID is VARCHAR TYPE
The issue is clear here. You can not pass string format because compiler compiles parameter before converting into string format. From your method declaration allowed parameters must be 3.
So compiler detect 4 parameter as you pass string with format.
Also in sqlite database for VARCHAR type field use double quotes for field values.
So your string should be like this:
NSString *whereClauseString = [NSString stringWithFormat:#"MESSAGE_ID = \"%#\"",#"hai"];
Or if value is pre known simply create string like this:
NSString *whereClauseString = #"MESSAGE_ID = \"hai\"";
And then use this string as third parameter for updateTable method:
[DataCachingHelper updateTable:#"sendertable" data:dic3 where:whereClauseString];
make this in two step.
NSString *strWhere=[NSString stringWithFormat:#"MESSAGE_ID='%#'",#"hai"];
[DataCachingHelper updateTable:#"sendertable" data:dic3 where:strWhere];

Grails- Exception when rendering Joda dates as JSON

I'm trying to render command validation errors as json but I'm getting an exception. The command object is using joda time DateTime objects instead of java.util Date objects. The code to do the json rendering looks like:
def results = eventSaleDataCommand.errors.fieldErrors.toList()
def errors = []
for (error in results) {
errors.add([
'type' : 'invalid_entry',
'field' : error.field,
'rejected_value': error.rejectedValue,
'message' : error.defaultMessage
])
}
render errors as JSON
The exception I'm getting is:
Class org.codehaus.groovy.grails.web.converters.marshaller.json.GenericJavaBeanMarshaller can not access a member of class org.joda.time.tz.DateTimeZoneBuilder$PrecalculatedZone with modifiers "public".
Anyone know how to get around this?
Implementing a Joda converter did the trick. Thanks.

Resources