Grails 2.5.3 not binding float fields correctly - grails

I have a domain class with a float field:
class DvQuantity {
float magnitude
String units
}
When I have this:
new DvQuantity( magnitude: '11.0', units: 'm' ).save()
In the database I see: magnitude = 110.0 instead of 11.0
Is this a Grails bug? Is there any workaround?

It is not a bug. As stated in the comment, parsing of numbers depends on your locale. See example below:
import java.text.NumberFormat
String a = '11,0'
assert NumberFormat.getInstance(Locale.US).parse(a).floatValue() == 110
assert NumberFormat.getInstance(Locale.FRANCE).parse(a).floatValue() == 11.0
There are many different ways to change your default number format - for example PropertyEditorRegistrar or ValueConverter. You can also enforce format on the view using validators.
Here Grails databinding with decimal delimiter is answer with example code how to do that for Grails <2.3 and >=2.4

Related

Spatial querydsl - GeometryExpressions. Find entities that range contains given "Point"

Used tools and their versions:
I am using:
spring boot 2.2.6
hibernate/hibernate-spatial 5.3.10 with dialect set to: org.hibernate.spatial.dialect.mysql.MySQL56SpatialDialect
querydsl-spatial 4.2.1
com.vividsolutions.jts 1.13
jscience 4.3.1
Problem description:
I have an entity that represents medical-clinic:
import com.vividsolutions.jts.geom.Polygon;
#Entity
public class Clinic {
#Column(name = "range", columnDefinition = "Polygon")
private Polygon range;
}
The range is a circle calculated earlier based on the clinic's gps-location and radius. It represents the operating area for that clinic. That means that it treats only patients with their home address lying within that circle. Let's assume that above circle, is correct.
My goal (question):
I have a gps point with a patient location: 45.7602322 4.8444941. I would like to find all clinics that are able to treat that patient. That means, to find all the clinics that their range field contains 45.7602322 4.8444941.
My solution (partially correct (I think))
To get it done, I have created a simple "Predicate"/"BooleanExpression":
GeometryExpressions.asGeometry(QClinic.clinic.range)
.contains(Wkt.fromWkt("Point(45.7602322 4.8444941)"))
and it actualy works, because I can see proper sql query in console:
select (...) where
ST_Contains(clinic0_.range, ?)=1 limit ?
first binding param: POINT(45.7602322 4.8444941)
But I have two problems with that:
QClinic.clinic.range is marked as "warning" in intellij as: "Unchecked assignment: 'com.querydsl.spatial.jts.JTSPolygonPath' to 'com.querydsl.core.types.Expression<org.geolatte.geom.Geometry'". Yes, in QClinic range is com.querydsl.spatial.jts.JTSPolygonPath
Using debugger and intellij's "evaluate" on the above line (that creates the expression) i can see that there is an error message: "unknown operation with operator CONTAINS and args [clinic.range, POINT(45.7602322 4.8444941)]"
You can ignore the second warning. The spatial specific operations are simply not registered in the serializer used for the toString of the operation. They reside in their own module.
The first warning indicates that you're mixing up Geolatte and JTS expressions. From your mapping it seems you intend to use JTS. In that case you need to use com.querydsl.spatial.jts.JTSGeometryExpressions instead of com.querydsl.spatial.jts.GeometryExpressions in order to get rid of that warning.

Spock datatable just accepting integers in Speck inputs

I'm working in migrating a large application from Grails 3.3 to Grails 4.
On of the issues we got is related to Spock, the functionality we used in Grails 3.39 seems to be missing: whe using a datatable to represent the specs, the column for the inputs, seems to be accepting jus integers values
In the below code just the first line of the specks is passing the text. No the next two, as the spock is transforming to integer befor passing it to Math.round(value)
import spock.lang.*
#Unroll
void 'test to demostrate Spock is just accepting integer in datatable column value'() {
expect:
Math.round(value) == result
where:
value | result
1234 | 1234
4321.56d | 4322d
1111.56f | 1112d
}
I was noty getting this issue in version 3.3 of Grails.
Thanks in advance for attend this issue
Juan
UPDATE:
UPDATE:
The change of behavior described, actually occurs when the test based on datatable is preceded by a test that includes throwing an excetion
WORK AROUND:
Move the test that includes the exception throwing to be the last test.
Grails 4 uses org.spockframework:spock-core:1.2-groovy-2.5 and in this version it works as expected (as in other versions of Spock).
Update your specification in this way:
import spock.lang.Specification
import spock.lang.Unroll
class RoundSpec extends Specification {
#Unroll
void 'Math.round(#value) == #result'() {
setup:
println "$value as ${value.class}"
expect:
Math.round(value) == result
where:
value || result
1234 || 1234
4321.56d || 4322
1111.56f || 1112
}
}
Then you can see that all test cases pass the test and you can also see in the output what data of which class is passed into the test:
So Integer, Double and Float are passed and not Integer in all cases as you write.
What I can see in your test is, that you have result value as a Double two times, but Math.round() returns long each time.

Default string size for Postgresql and Grails 3.3.8 seems to be 20 characters

My string columns are defaulting to 20 characters. All the documentation suggests the default is 255. How do I set that without changing each individual column. I am using Grails 3.3.8 and Postgresql 9.3.
class DbConnection {
String name
String platform
creates 20 character columns
If I add a mapping:
static mapping = {
name sqlType: 'varchar(255)'
platform sqlType: 'varchar(255)'
url sqlType: 'varchar(255)'
}
I get the proper 255 characters, however, grails fails the string on validation:
Field error in object 'dop_etc.DbConnection' on field 'url': rejected value [localhost:5432/rbc48_fantasy]; codes [dop_etc.DbConnection.url.size.error.dop_etc.DbConnection.url,dop_etc.DbConnection.url.size.error.url,dop_etc.DbConnection.url.size.error.java.lang.String...
There seems to be a default size set somewhere and I can't seem to find it. Thanks for your responses.
Apologies, found the problem in some pasted code (in application.groovy)
grails.gorm.default.constraints = {
'*'(nullable: true, size: 1..255)
}
Here's the helpful article:
Overriding default `maxSize` in domain class

Store phoneNumbers in Grails Domain Classes?

I want to store phone numbers in Grails domain classes. I am not sure what is the best way of doing this. Storing as int does not seems to be a good idea because leading zero is impossible for that.
What is the best way to store and validate phone numbers in Grails domain classes?
I would store phone as a String - nullable and blank too. For display purposes, simply provide your own tag in grails's tablib package.
For example, with a property inside some domain class like this:
String phone
And a taglib class like this:
class MyTagLib {
static defaultEncodeAs = [taglib:'html']
def phone334 = { attrs ->
String phone = attrs.phone
def formatted =
"(".concat(phone.substring(0, 3)).concat(") ")
.concat(phone.substring(3, 6)).concat("-").concat(phone.substring(6))
out << formatted
}
}
and a usage like this inside a gsp:
<g:phone334 phone="${theInstance.phone}" />
Then if phone = '4165557799', the output would be displayed like this: (416) 555-7799.
You can build as many formatters as you want; for example, if your number is 011218213334488 and you need it to look like +(218) 21 333 4488, simply build a formatter for that depending on the length and/or the pattern detected in the input.
You can also build simple validators right there too to make sure for example that all characters are made up of digits and parentheses and dashes, but I don't think taglibs are the right place for that - perform a bit of filtering and validation as suggested in the other posts before getting to displaying what should be correct input material.
You could most probably use matches constraint and store phone numbers as String as there is no predefined constraints for phone numbers. There in matches you can use any regex pattern required according to your needs.
static constraints = {
phone(matches: "^(?:0091|\\+91|0)[7-9][0-9]{9}$")
}
The above regex will work like :-
Begins with 0, +91 or 0091
Followed by a 7-9
Followed by exactly 9 numbers
Must match entire input
You can change it according to your needs.
You can store the phone number as string. To validate the phone number you can use google phone number java library to validate international numbers. Or more easily you can use this grails plugin in your code: https://github.com/ataylor284/grails-phonenumbers . Here is a sample from the plugin home page.
class MyDomain {
String phoneNumber
static constraints = {
phoneNumber(phoneNumber: true)
}
}
Edit:
To validate the number if it is not blank you have to define your custom constraint class which extends PhoneNumberConstraint class.
class CustomPhoneNumberConstraint extends PhoneNumberConstraint{
#Override
protected void processValidate(target, propertyValue, Errors errors) {
//check if phone number is blank
if (propertyValue instanceof String && GrailsStringUtils.isBlank((String)propertyValue)) {
if (!blank) {
super.processValidate(target,propertyValue, errors)
}
}
return true
}
}

Grails BigDecimal constraints not working

I am using Grails version 2.3.3, and groovy version 2.1.8.
I am using an online tutorial to help learn Grails web dev, and I have created a domain class with the following constraints
package racetrack
class Race {
static constraints = {
name(blank:false, maxSize:50)
city(blank:false)
state(inList:["GA", "NC", "SC", "VA"])
startDate()
distance(min: 0.0)
cost(min: new BigDecimal(0.0), max: new BigDecimal(100.0))
maxRunners(min:0, max:100000)
}
String name
Date startDate
String city
String state
BigDecimal distance
BigDecimal cost
Integer maxRunners
}
I'm using scaffolding so I have full CRUD functionality. The problem is, when I go to create a new Race, the app allows me to input values like "-1" in both the distance and cost fields, and values like "200" for the cost field. I noticed that the Integer field maxRunners was working correctly, as it displays a warning message if I try to put in -1 maxRunners. I changed the cost field to be of type Integer, and then the constraints started working.
Why is this happening? I copy and pasted the code from the tutorial into my text file and the constraints to not work for BigDecimal type fields.
According to the docs for the min and max constraints, the parameter must be
a class that implements java.lang.Comparable. The type of the value must be the same as the property.
so I can't see any reason why your definition shouldn't work. As a workaround, you could try replacing this
cost(min: new BigDecimal(0.0), max: new BigDecimal(100.0))
with
cost(range: 0..100)
and you could replace this constraint:
distance(min: 0.0)
with a custom validator, e.g.
distance validator: {
it >= 0.0
}
I've just noticed the following oddity which appears before the 2 problematic constraints
startDate()
Perhaps replacing it with either:
startDate(nullable: true)
or
startDate(nullable: false)
might fix the problem?
Doesn't Groovy use java.math.BigDecimal by default? Could you change new BigDecimal(0.0) to simply 0.0 and new BigDecimal(100.00) to 100.00 like this:
cost(min: 0.0, max: 100.0)
Here is the documentation that states:
To support the 'least surprising' approach, groovy literals with decimal points are instantiated as java.math.BigDecimal types rather than binary floating point types (Float, Double).
Also, you could try forcing it by using the G suffix like this:
cost(min: 0.0G, max: 100.0G)

Resources