Spring Boot and RethinkDB save JSON of unknown structure - java

I develop Spring REST API. One of its endpoints must receive JSONs of unknown structure. To be exact, all JSONs has common header, but the inner document differs:
{
"receiveData": {
"iBusData": {
"requestUID": "11111111-2222-3333-4444-555555555555",
"messageKind": "PublishedData",
"sender": "ST-DELLIN-307",
"senderDateTime": "2018-10-15T09:09:09",
"typeName": "typeContractor",
"currentSenderApplication": "GP",
"objectUID": "09876543-rrrr-aaaa-nnnn-ddddddddddddd",
"data": {
"contractor": {
"uid": "09876543-rrrr-aaaa-nnnn-ddddddddddddd",
"name": "Test_Contractor",
"marked": false,
"code": "763764568763",
"isGroup": false,
"fullName": "Test_Contractor",
"INN": "Test_Contractor",
"personalIDKindName ": "Test_Contractor",
"personalIDSeries": "7634",
"personalIDNumber": "18-111111111",
"contractorCategory": "Test_Contractor",
"contractorOPF": "Test_Contractor",
"federalCategory": "Test_Contractor",
"regionalCategory": "Test_Contractor"
}
}
}
}
}
Payload of data field may be different. All this nested documents (contractor in the example above) need to be stored in JSON-oriented database RethinkDB.
How to implement endpoint that cat receive JSONs with different structured in the data field?
Now I thought up to parse all JSONs as HashMap:
public ResponseEntity<?> all(#RequestBody HashMap json)
split HashMap to header and document and to store in database. But there are some difficulties:
I need to select stored documents in the same format that they comes to endpoint
I need to compare nested documents using SHA256 and update them in the database
I need to add three custom fields to the document before storing in the database
How to do all this?

You can create a classes for the body that has the common fields [you call a header].
Request body class
class MyRequest {
BusData iBusData;
}
Class to hold the dynamic data
class BusData {
String requestUID;
String messageKind;
// other fields
// unknown json structure
HashMap<String, Object> data;
}
When you receive this type of request body, to insert in reThinkDB - I think you could iterate the keys/values in the hashmap, and determine if the value is another object, then recursively iterate, building a query.
You'll probably need to pass the querybuilder parts by reference to methods during the recursion.
I don't have experience with rethinkdb, so I can't provide an implementation here.

Related

Convert only whitelisted properties from JSON to Map<String, Object>

Want to convert incoming JSON to a Map<String, Object> but with the following requirements:
Unknow properties should not cause exceptions (objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)).
Only whitelisted properties of the incoming JSON should appear in the Map (with the above configuration even unknown properties would be present in the Map).
The whitelisted properties should automatically correspond to the fields of a POJO.
Converting the JSON directly to my POJO would take care of points 1, 2, and 3, but I would lose the knowledge of which properties were included in the incoming JSON, that's why I want to convert to a Map.
Going from JSON to POJO to Map (let's call it Map2) would also work, but then any primitive fields in the POJO would have default values in Map2, even though they were absent in the JSON.
Put another way, I want the fields in the resultant Map to be the intersection of the properties of the JSON and the fields in the POJO.
For example, given the JSON:
{
"name": "ABCD",
"_email": "abcd#example.com",
"roles": [
"USER"
]
}
where name and roles are valid fields in the POJO (email is valid, but not _email), I want to end up with the Map:
{
name: "ABCD",
roles: [ "USER"]
}
Don't want to have to hand-code the list of valid field names for the various POJOs.

Remove Elements from JSON String

I have a JSON string as follows:
{
"account": "1234",
"type": "ar-type",
"eventTypes": "Update",
"objectClassName": "com.triype",
"objectJson": "{\"Name\":\"pdpot\",\"traptype\":\"adpot",\"displayName\":\"pdpot",\"experimentName\":\"pdpotpie\",\"creationTime\":\"Mar 18, 2020 5:58:58 PM\",\"createdBy\":{\"userProfileOne\":\"s:pdx\",\"userProfileTwo\":\"sid\",\"domainId\":\"did:pdx-tod-64003\"},\"lastModifiedBy\":{\"userProfileArn\":\"s:pdx-tod-64003\"},\"createdBy\":{\"userProfileOne\":\"s:p\",\"userProfileTwo\":\"si\",\"domainId\":\"did:ppot\"}}}
}
I get this input as a string and before passing it as a string to a parser I need to perform some string filtering and remove all "userProfileOne", "userProfileTwo","domainId" and their keys, without compromising the JSON structure. I am currently writing this code in Java using gson and json.
Note: There are multiple occurences of UserProfileOne, UserProfileTwo and DomainID.
The required Output is as follows:
{
"account": "1234",
"type": "ar-type",
"eventTypes": "Update",
"objectClassName": "com.triype",
"objectJson": "{\"Name\":\"pdpot\",\"traptype\":\"adpot",\"displayName\":\"pdpot",\"experimentName\":\"pdpotpie\",\"creationTime\":\"Mar 18, 2020 5:58:58 PM\"}}
}
Currently I am using substringBetween. But the operation does not work as intended.
A potential approach is to deserialize the json into a java structure then filter this structure by set to null fields you don't want to be serialize.
By using framework like Jackson you can set this before serialization on the ObjectMapper
mapper.setSerializationInclusion(Include.NON_NULL). So all null values won't be serialized in the final json/result.
I think the best maintainable way would be to create a class structure corresponding to that json and map it to the class.
Use #JsonIgnore on the fields to be ignored and then map it back to JSON from the class structure.
Another approach, a bit complex to implement, is to go through each node in the json and remove that node if it's not required
You can also do it by string matching but I don't think that is a good approach.

How to get the set inside nested JsonNode using Jackson

I have a below JSON structure. which I need to parse using the Jackson library. I am building a web-service, which accept below JSON in a POST method's BODY.
{
"organization": {
"products": [
"foo",
"bar",
"baz"
]
},
"mission" : "to be the best in domain"
}
Till, now I was having simple JSON body, which wasn't having nested and JSON element, like in this case organization is another JSON node which contains a Set of products.
This JSON keys are not mandatory, And I am accepting/storing organization JSON in JsonNode. And doing below checks.
If organization is null.
If organization is not null and it has products key.
But after that I don't know how to fetch the set of boards from this JsonNode and store it in Java's HashSet.
My expected O/P should be to have a set of boards extracted from my organization JsonNode.
P.S. :- I think I have to use the ObjectMapper but couldn't find a direct way of getting the Set. Looks like I need to use some JsonParser with which I am not very familier.
You can create DTOs(Data Transfer Objects) for your purpose. The nested objects could have the structure as below:
class Organization {
List<String> Products;
.....
}
class WebOrganizationRequest {
Organization organization;
String mission;
}
By creating objects in this way you are mapping your JSON objects to classes and Jackson will typecast the JSON as an instance of WebOrganizationRequest when you pass it in the controller with WebOrganizationRequest as the request body type.

Jersey - Moxy returning appended json in class property

I have a Jersey client that makes a call to a 3rd party rest api and retrieves some JSON.
{"A":1,"W":2,"List":[{"name":"John","amount":10.0}]}
After that I need to append this JSON to my response class and give it back in the response.
#XmlRootElement
public class MyResponse {
private JsonObject body;
private String status;
I manage to assign the value that comes from the 3rd party api to body but the response that's sent is like this:
{
"status": "success",
"body": {
"entry": [
{
"key": "A",
"value": 1
} ,
{
"key": "W",
"value": 2
},
{
"key": "List",
"value": "[{\"name\":\"John\",\"amount\":10.0}]"
}
]
}
}
So there are two main issues, moxy is generating key and value elements while I would like it to be key: value and also it is not generating properly the 2nd level objects in the JSON structure provided by the API.
MOXy is a JAXB implementation, while JsonObject is part of JSON-P. MOXy happens to be able to deal with JSON too, but that is a proprietary extension over the JAXB standard. As far as I know, there is no default mapping available between JSON-P and JAXB. The reason you're seeing those key/value entries must be because JsonObject extends java.util.Map, so you get the default MOXy mapping for that type.
I think you have the following possibilities:
Go with either JSON-P or JAXB/MOXy (MOXy required for its additional JSON binding) only.
Use one of the JAXB/MOXy mechanisms for mapping custom types from/to JAXB. The standard way is to use an XmlAdapter, examples for dealing with Maps in particular are here and here. But I think this will be difficult if you don't know the structure of the 3rd party JSON content and want to keep nested levels intact.
Yet another possibility might be to use a proprietary API like Jackson, but I can't help with that.

Internal object representation when designing JSON apis

I've got an object design question.
I'm building a json api in Java. My system uses pojos to represent json objects and translates them from json to pojo using Jackson. Each object needs to take different forms in different contexts, and I can't decide whether to create a bunch of separate classes, one for each context, or try to make a common class work in all circumstances.
Let me give a concrete example.
The system has users. The api has a service to add, modify and delete uses. There is a table of users in a database. The database record looks like this:
{
id: 123, // autoincrement
name: "Bob",
passwordHash: "random string",
unmodifiable: "some string"
}
When you POST/add a user, your pojo should not include an id, because that's autogenerated. You also want to be able to include a password, which gets hashed and stored in the db.
When you PUT/update a user, your pojo shouldn't include the unmodifiable field, but it must include the id, so you know what user you're modifying.
When you GET/retrieve the user, you should get all fields except the passwordHash.
So the pojo that represents the user has different properties depending on whether you're adding, updating, or retrieving the user. And it has different properties in the database.
So, should I create four different pojos in my system and translate among them? Or create one User class and try to make it look different in different circumstances, using Jackson views or some other mechanism?
I'm finding the latter approach really hard to manage.
In my opinion you should create only one POJO - User which has all needed properties. And now you should decide whether your API is rigorous or lenient. If your API is rigorous it should return error when it receives wrong JSON data. In lenient version API can skip superfluous (unnecessary) properties.
Before I will provide an example, let me change the 'passwordHash' property to 'password'.
Add new user/POST
JSON data from client:
{
id: 123,
name: "Bob",
password: "random string",
unmodifiable: "some string"
}
Rigorous version can return for example something like this:
{
"status": "ERROR",
"errors": [
{
"errorType": 1001,
"message": "Id field is not allowed in POST request."
}
]
}
Lenient version can return for example something like this:
{
"status": "SUCCESS",
"warnings": [
"Id field was omitted."
]
}
For each CRUD method you can write a set of unit tests which will be holding information which way you choose and what is allowed and what is not.

Categories

Resources