Micronaut CompileStatic JSON object -Static type checking- No such property: bookid for class: java.lang.Object - groovy

In my Micronaut Controller I have below code to parse the JSON object. when I use #CompileStatic annotation it throwing this below error.
#Post("/save")
def save(#Body Object JSON) {
String bookid=JSON?.bookid
String name=JSON?.name
def b =bookService.save(bookid,name)
return HttpResponse.created(b)
}
Error
BookController.groovy: 58: [Static type checking] - No such property: bookid for class: java.lang.Object
Is there way to fix this error message with compilestatic annotation?
Thanks
SR

With Help of Jeff Brown I have changed. my save method like this.
#Post('/')
Book save(Book b) {
bookService.save b
}
Micronaut JSON post strip the Qutoes

You can also work with your method instead of changing it for parsing.I encountered the same problem and the method that worked for me is using String instead of object. Just use JSON String along with #BODY and then parse it using ObjectMapper().
here is the answer i posted at some other question, hope it will help you out.
https://stackoverflow.com/a/54905403/7803105

Related

Add strong typing to objects from JsonSlurper

I'm having some trouble getting typing to work with the JsonSlurper in Groovy. I'm fairly new to Groovy, and even newer to adding strong types to it - bear with me.
Right now I've created a trait which defines the general shape of my JSON object, and I'm trying to cast the results of parseText to it.
import groovy.json.JsonSlurper
trait Person {
String firstname
String lastname
}
def person = (Person)(new JsonSlurper().parseText('{"firstname": "Lando", "lastname": "Calrissian"}'))
println person.lastname
This throws
Exception in thread "main" org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object '{firstname=Lando, lastname=Calrissian}' with class 'org.apache.groovy.json.internal.LazyMap' to class 'Person' due to: groovy.lang.GroovyRuntimeException: Could not find matching constructor for: Person(org.apache.groovy.json.internal.LazyMap)
...
I can see why my code doesn't make sense, I'm not trying to change the type of the data (casting), I'm just trying to let my IDE know that this is what's inside of my object.
Is it possible to at least add code completion to my JSON objects? I'd love to get runtime type checking, as well, but it's not necessary.
you could try to use delegate
this allows to wrap class around map
import groovy.json.JsonSlurper
class Person {
#Delegate Map delegate
String getFirstname(){ delegate.get('firstname') }
String getLastname(){ delegate.get('lastname') }
}
def person = new Person(delegate:new JsonSlurper().parseText('{"firstname": "Lando", "lastname": "Calrissian"}'))
println person.lastname
or for example use Gson for parsing:
#Grab(group='com.google.code.gson', module='gson', version='2.8.5')
import com.google.gson.Gson
class Person {
String firstname
String lastname
}
def person = new Gson().fromJson('{"firstname": "Lando", "lastname": "Calrissian"}', Person.class)
assert person instanceof Person
println person.lastname
This actually is a cast and Groovy will try to turn your Map into said object.
From the docs:
The coercion operator (as) is a variant of casting. Coercion converts object from one type to another without them being compatible for assignment.
The way this works for a POJO is to construct a new object using the Map-c'tor. This will either unroll into calling setters or works directly with static compilation.
Be aware, that using maps with excess keys will lead to errors. So I'd only use this for toy projects. Use a proper JSON-mapper like e.g. Jackson instead.
So the solution here is to not use a trait (which is basically a interface) but a regular class.

How to cast groovyx.net.http.HttpResponseDecorator to user defined class

I am writing a Integration Test class using Spock Framework, there my response hold inside groovyx.net.http.HttpResponseDecorator
I am trying to cast into my own class lets say TestEntity using following step
HttpResponseDecorator response = getRestClient().delete([path: "$BASE_URL"+"/96023"])
Here the Path method returns TestEntity, Now I want to get that entity and write assertions
TestEntity entity = (TestEntity)response.getData()
When I write this statement I am getting ERROR!
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object
What class is returned by getData() depends on what content type returns the REST API you are calling.
Add this line to check what class is Groovy using in your case:
println response.data.getClass()
... or use debug in your IDE to obtain the same information.
For example for content type:
application/json class org.apache.groovy.json.internal.LazyMap is used
application/xml class groovy.util.slurpersupport.NodeChild is used
text/plain class java.io.StringReader is used
If you are testing backend which uses the TestEntity class as a response (for example using #RestController and #RequestMapping in Spring) then you will not have TestEntity instance in the client (Spock test).

Groovy trait: cannot find matching method error

I'm trying to use Spock and Groovy for testing. I have written simple class/trait for testing as follows:
import com.plomber.user.domain.UserDto
import groovy.transform.CompileStatic
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
#CompileStatic
trait SampleUsers {
UserDto John = createDto(1, "john#example.com", "simpleJohn1")
UserDto Bob = createDto(2, "Bob#example.com", "simpleBob1")
static private UserDto createDto(Integer id, String email, String password) {
return UserDto.builder()
.id(id)
.email(email)
.password(new BCryptPasswordEncoder().encode(password))
.build()
}
}
I'm getting following error when I try to compile it:
Error:(10, 20) Groovyc: [Static type checking] - Cannot find matching method com.plomber.SampleUsers#createDto(int, java.lang.String, java.lang.String). Please check if the declared type is right and if the method exists.
If I assign John and Bob fields using UserDto.builder().id(id) ... instead of createDto() method - it works as expected. Do I miss something?
From groovy docs:
Traits with static methods cannot be compiled statically or type
checked. All static methods/properties/field are accessed dynamically
(it’s a limitation from the JVM).
http://docs.groovy-lang.org/next/html/documentation/core-traits.html#_static_methods_properties_and_fields

Trivial deserialization failing with YamlDotNet

What can possible go wrong with this:
public void Main()
{
var input = new StringReader(Document);
var deserializer = new Deserializer(namingConvention: new CamelCaseNamingConvention());
var p = deserializer.Deserialize<Person>(input);
Console.WriteLine(p.Name);
}
public class Person
{
public string Name {get;set;}
}
private const string Document = #"Name: Peter";
A serialization exception is thrown:
Property 'Name' not found on type 'YamlDotNet.Samples.DeserializeObjectGraph+Person'
The same happens if I first serialize a Person object using the Serializer.
While the online sample for deserialization works just fine - this trivial code does not. What am I missing? It must be a stupid little detail. (But it happened before with other data structures I tried.)
As it seems, the problem is with the namingConvention parameter. If I don't set it to an instance of CamelCaseNamingConvention all is fine.
Unfortunately the "canonical" example (https://dotnetfiddle.net/HD2JXM) uses it and thus suggests it is important.
For any reason the CamelCaseNamingConvention converts the fields to lowercase in the class (ie. 'Name' to 'name'). As the string is 'Name' and not 'name' the deserialization fails. The example uses lower-case therefore it works....
I had the same problem....

groovy "with" block usage query

I am trying to use the with block in Groovy to easily initalize my class, but I am getting the following error. Could anyone tell me what I am doing wrong?
MyXMLTemplate template = new MyXMLTemplate ().with {
TxId = 'mnop'
oapTxId = 'abcd'
}
The error I get is:
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'abcd' with class 'java.lang.String' to class 'org.example.MyXMLTemplate'
at org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.castToType(DefaultTypeTransformation.java:331)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.castToType(ScriptBytecodeAdapter.java:599)
I am using groovy 1.8.0
You need to return the template itself from the with block:
MyXMLTemplate template = new MyXMLTemplate ().with {
TxId = 'mnop'
oapTxId = 'abcd'
it
}
It's hard to see what the problem is without seeing the definition of your class. I'll assume that TxId and oapTxId are both properties of the class.
I suspect your error is caused by oapTxId being of type MyXMLTemplate, and so not assignable from String.
Incidetally, as your with block is just initializing class properties, you could use the more idiomatic constructor and setters approach:
MyXmlTemplate template = new MyXMLTemplate(TxId: 'mnop', oapTxId : 'abcd')

Resources