Spring Boot - ignore root element in decoding - spring

A remote server sends a response in this format
{
"data": {
"item": {
a: ...
b: ...
}
}
}
In my spring application, I would like to decode this way directly. Instead of creating a Class for data.
record Item(String a, String b){}
Any idea how it can be done?
I already tried this. but no help.
spring.jackson.deserialization.UNWRAP_ROOT_VALUE=true
#JsonRootName("data")
record Item(String a, String b){}

You can deserialize just the {"a": "aValue", "b": "bValue"} json part of your json using the JsonNode#at method that returns a JsonNode node that will be converted to your Item object with the ObjectMapper#treeToValue method like below:
//pointing to the /data/item node
JsonNode itemNode = mapper.readTree(json).at("/data/item");
//Item will contain a=aValue and b=bValue
Item item = mapper.treeToValue(itemNode, Item.class);

Related

How to create dynamic nested object message in protoBuff?

Am trying to create a message of nested dynamic objects
The resulting ending data structure should look like this
"content": {
"foo1": "bar1",
"foo2": "bar2"
}
Where the keys and, the values inside the content is dynamic and can be defined by the client.
You can define content as a map<string, string>, so that clients can set any arbitrary key-value pairs (of string type) to it.
message Msg {
map<string, string> content = 1;
}
If the value might be any arbitrary types, you can try google.protobuf.Struct.

Spring boot: mockMvc testing controller: Expected: Entity, Actuall: null

How looks my json:
event object
{
...
"game": {
//game fields
}
}
...
}
I am trying to do:
event.setGame(new Game());
And check if there is my value by mockMvc
.andExpect(jsonPath("$.game").value(event.getGame()))
But i am getting error:
java.lang.AssertionError: JSON path "$.game"
Expected : Event(id= null, name= null, ...)
Actual :null
Why i am getting null, if i should get just empty game?
P.S. even if i set fields to game, i will get null
I make .andDo(print), and get :
Body = // event
{
"id":"5f087eec-8bf0-11eb-8dcd-0242ac130003",
"game":
{
"id":null,
"team1":null,
"team2":null,
"gameDate":null,
},
"user":
{
//user fields
}
}
How looks controller:
#GetMapping("/{id}")
public ResponseEntity<GetEventById> getEventById #PathVariable("id") String id) {
GetEventByIResponse dto= service.getEventById(id);
return ResponseEntity
.status(HttpStatus.OK)
.body(dto);
}
In my test i am creating GetEventByIResponse, how it looks:
public class Event {
private String id;
private Game game;
...
}
The JsonPath assert works as follows:
It first parses the path result into a Map/List/Object, to see if the origin was an array/object/simple type.
Then, if it's a Map (like in your case) it tries to parse the path result into the same type as the expected object.
Finally it compare the created object to the expected object using equals().
In your case I see several problems:
The AssertionError talks about an Event although you seem to hand in a Game.
We do not know if the serialization/deserialization works at all
Maybe you should try one of the following:
Place a breakpoint right here to watch the assert steps in your debugger:
Start with simple type comparisons:
.andExpect(jsonPath("$.id").value("foo"))
.andExpect(jsonPath("$.game.id").value("bar"))
Seems like the json path referencing the game child object is incorrect, try below:
.andExpect(jsonPath("$.event.game").value(event.getGame()))

How to add message type as object in ProtoBuf (gRPC) - Proto3 Syntax?

How to send message type as object in ProtoBuf - Proto3 Syntax?
I want to transfer object instead of string or number.
Example
{
name: 'One',
date: 'date',
some: 'some',
...
...
}
syntax = "proto3";
package db;
service Proxy
{
rpc myFunction(Request) returns (Response);
}
message Request
{
string name = 1;
}
message Response
{
object keyvalue = 1;
}
Here, I am getting error
throw Error("no such Type or Enum '" + path + "' in " + this);
^
Error: no such Type or Enum 'object' in Type
--
Workaround
I can convert it to string in server side, and then I can JSON.parse() at client.
But I want to know, if there any better way to do it.
protocol-buffer does not support the object data type!
But you can emulate your data as hierarchically by using protocol buffer message type itself.
syntax = "proto3";
package db;
service Proxy
{
rpc myFunction(Request) returns (Response);
}
message Request
{
string name = 1;
}
message Response
{
message obj {
string key1 = 1;
string key2 = 2
}
obj keyvalue = 1; // Here you have created your own type obj.
}
In the above example, you can see that the Response message now has "keyvalue" field of type obj(which is a custom type you have just built).
Now you will pass Object in a callback from the server instead of primitive type.
callback(null, { keyvalue: { key1: "value1", key2: "value2" } });
Let's say if keys are unknown to you but key/value pair data type is same and known to you then, in this case, you can use
map<type, type>
message Response
{
map<string, string> keyvalue = 1;
}
callback(null, { keyvalue: { "key1": "value1", "key5": "value2" } });
References:-
https://developers.google.com/protocol-buffers/docs/proto3#other
https://developers.google.com/protocol-buffers/docs/proto#scalar
https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.Struct
Depending on what you're trying to accomplish, you can likely use one of three types.
The bytes type represents an arbitrary string of bytes. You can choose to encode your types in anyway you feel appropriate.
The any type represents an arbitrary protobuf message, allowing the client or server to encode non-predefined messages. This is a string of bytes, with a unique identifier per message type and language implementations will have ways to unpack the message.
You mention using Javascript. You could likely define a Javascript object message using a combination of oneof for the basic types and map for object types.
If all of the keys and values you want to send have the same type, you can use a map type. Your example shows string keys and string values, so that could use the type map<string, string>.
If you want to send arbitrary object data with similar structure to JSON objects, you can use the google.protobuf.Struct message type.

Grails: POST or GET httprequest params only

In controller and gsp there are avaliable two variables:
params - tahat contains map of all params (both GET from Query String and POST from forms)
request - the HttpServletRequest object
How can I get POST only params or GET (query string) only params? I need both types of params but in different maps.
I know, that HttpServletRequest object contains information about Query String, but I'm looking for solution without implementing parser of query string.
I have solved this problem by parsing Query String with org.codehaus.groovy.grails.web.util.WebUtils and then I put these data into HttpServletRequest attribute.
Now I can use request.getAttribute('paramsGet') or request.getAttribute('paramsPost').
The Grails filters was very helpfull, so:
package com.selly.filters
import org.codehaus.groovy.grails.web.util.WebUtils
class ParamsFilters {
List globalParams = [
"controller",
"action",
"format"
]
def filters = {
all(controller:'*', action:'*') {
before = {
Map paramsRequest = params.findAll {
return !globalParams.contains(it.key)
}
Map paramsGet = WebUtils.fromQueryString(request.getQueryString() ?: "")
Map paramsPost = paramsRequest.minus(paramsGet)
request.setAttribute('paramsGet', paramsGet)
request.setAttribute('paramsPost', paramsPost)
//println request.getAttribute('paramsGet')
//println request.getAttribute('paramsPost')
}
after = { Map model ->
}
afterView = { Exception e ->
}
}
}
}
Even with Grails, you're working with Servlet which mix up POST and GET. And I don't remember seeing something (except for reparsing the Query String) which would help you.

Spring Restful issue with list of length 1

We are having a json which shows a list of object as below:
skillCheckAnswers: [
{
optionId: 6786,
optionText: "Copy constructor",
optionWeight: "1.00"
},
{
optionId: 6787,
optionText: "Friend constructor",
optionWeight: "2.00"
},
{
optionId: 6788,
optionText: "Default constructor",
optionWeight: "3.00"
},
{
optionId: 6789,
optionText: "Parameterized constructor",
optionWeight: "4.00"
}
]
Which is ok as long as there are more than 1 object in the list. But if the list contains only 1 item then the json displays :
{
optionId: 6785,
optionText: "Friend class",
optionWeight: "4.00"
}
Please note that the second Json is not given as a List but as a single object ( missing square braces[] ).
Is there a way where I can output the list of length 1 with square braces?
Edit--
We can use foreach for the first JSON but foreach starts giving error if the number of object goes to 1. To handle this we are having an if else loop to check if the List is of length 1 or more than 1. If the list is of length then we handle this as a single obkect. This seems to be a stupid solution and I guess there would be an easy way out.
Can anyone tell me if this is even possible?
You should do something like:
From Spring controller:
#RequestMapping(method = RequestMethod.GET, value = "/myquestions")
public #ResponseBody
List<Answer> generateQuestions() {
List<Answer> answers = new ArrayList<Answer>();
Answer ans1 = new Answer();
ans1.setOptionId("6785");
ans1.setOptionText("Friend class");
ans1.setOptionWeight("4.00");
answers.add(ans1);
return answers;
}
The output is as follows:
[
{
"optionId": "6785",
"optionText": "Friend class",
"optionWeight": "4.00"
}
]
So far I understood, you problem is related to JSON converter. I have tested with Spring MappingJacksonHttpMessageConverter message converter. You can see Spring documentation for how to configure the JSON converter. http://static.springsource.org/spring/docs/3.0.0.M3/reference/html/ch18s02.html
You mentioned you use Spring. Doesn't Spring automatically look after JSON conversions for your the restful API it provides. You can put something like this is your conext file:
You can use org.springframework.http.converter.json.MappingJacksonHttpMessageConverter and set it up in your context file to do the JSON conversion for you.
Then you can use Spring MVC's #ResponseBody annotation to provide a restful service with having to handcode the JSON response.

Resources