Jackson JSON check values before adding them to list - java

Code snippet:
ObjectMapper objectMapper = new ObjectMapper();
try {
this.persons = objectMapper.readValue(new File(fileName),
new TypeReference<List<Person>>() {
});
} catch (IOException ex) {
}
Example json input:
[
{
"id": 1,
"name": "The Best",
"email": "thenextbigthing#gmail.com",
"birthDate": "1981-11-23"
},
{
"id": 2,
"name": "Andy Jr.",
"email": "usa#gmail.com",
"birthDate": "1982-12-01"
},
{
"id": 3,
"name": "JohnDoe",
"email": "gameover#gmail.com",
"birthDate": "1990-01-02"
},
{
"id": 4,
"name": "SomeOne",
"email": "rucksack#gmail.com",
"birthDate": "1988-01-22"
},
{
"id": 5,
"name": "Mr. Mxyzptlk",
"email": "bigman#hotmail.com",
"birthDate": "1977-08-12"
}
]
I'd like to know if it's possible (then how?) to check the values before creating an object and add it to the list. For example, i don't want the object being created and added to the list if the e-mail address or name is longer than 30 characters or if name matches certain regex expression etc. Instead I want to throw an IOException with something like "wrong input data". I'm not allowed to create more custom classes.

I believe you can't do this, because Jackson works on parsing, not for validation.
My suggestion:
public boolean checkJson(String jsonStr, Class<?> valueType) throws JsonParseException, IOException {
ObjectMapper mapper = new ObjectMapper();
try {
List<TypeHere> list = mapper.readValue(jsonStr, valueType);
return list.stream().anyMatch(s -> s.length() < 30);
} catch (JsonMappingException e) {
return false;
}
}
Instead return a boolean value, you can throw a Exception.
Obs: I'm working on my English yet. Please, feel free to edit.

Related

Trying to get specific data from a query response

I'm running a JUnit test, and I'm having some issues with a function where I have to get specific data from a query response. Here's a function I'm testing, note .get("data") at the end:
protected JsonNode getFunctionIds(FilterInputModel paramA) {
String paramB = "here's a query";
String idsQuery = setFunctionFieldsForQuery(paramA, paramB);
...
return Objects.requireNonNull(webClient.post()
.uri("/query")
.header(HttpHeaders.AUTHORIZATION, getSessionId())
.body(BodyInserters.fromMultipartData(queryMap))
.retrieve()
.bodyToMono(JsonNode.class)
.block())
.get("data");
}
Note that the inputModel is a class containing strings and string lists.
Here's a test I wrote. I'm getting an AssertionFailedError with it, and I vaguely know why, but I don't know how to get the right data.
#Test
void getFunctionIds() throws IOException {
Path filePath = Path.of("documents/__files/getFunctionIds.json");
String body = Files.read(filePath.toFile(), Charset.defaultCharset());
wireMockServer.stubFor(post(urlEqualTo("/api/query"))
.willReturn(aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBody(body))
);
JsonNode jsonNode = new ObjectMapper().readValue(body, JsonNode.class);
String bodyData = new ObjectMapper().writeValueAsString(jsonNode);
JsonNode vaultData = serviceTest.getFunctionIds(inputModel);
String response = new ObjectMapper().writeValueAsString(vaultData);
assertEquals(bodyData, response);
}
Next is a query response (paramB) I got when sending it to the vault. It is stored as a String bodyData.
{
"someOtherData": ...
{
...
},
"data": [
{
"id": "V4600000002G003"
},
{
"id": "V4600000002H214"
},
{
"id": "V4600000002I001"
},
{
"id": "V4600000002J001"
},
{
"id": "V4600000002J062"
},
{
"id": "V4600000002K047"
},
{
"id": "V4600000002K071"
},
{
"id": "V4600000002K171"
}
]
}
And as I said, all I got is an AssertionFailedError, because I'm asserting the whole query response (bodyData) with just the "data" part of the JSON, which is stored in String response.
Here's the error:
Expected :{
"someOtherData"... + "data", actually the whole query response (paramB) i mentioned already.
Actual:
[
{
"id": "V4600000002G003"
},
{
"id": "V4600000002H214"
},
{
"id": "V4600000002I001"
},
{
"id": "V4600000002J001"
},
{
"id": "V4600000002J062"
},
{
"id": "V4600000002K047"
},
{
"id": "V4600000002K071"
},
{
"id": "V4600000002K171"
}
]
Is there a way to catch just the Actual part of the query response, to avoid the AssertionFailedError? That would solve my problem, obviously.

How I can get List object from JSON instead of a LinkedHashMap?

I have this method which should return different objects from JSON, depending on the type of class in the argument.I tryed it to return a list of objects based on the argument, but I get only LinkedHashMap into ArrayList.
I searched a lot, but everywhere in the solutions the class type is hard-coded.
Is there a way to solve this problem without hard code?
public static <T> List<T> getObjects(Class<T> c) {
CloseableHttpClient rest = HttpClientSessionSingleton.getInstance().getHttpClient();
String urlRequest = (host + "/" +
c.getSimpleName().toLowerCase() + "s");
HttpGet httpGet = new HttpGet(urlRequest);
try (CloseableHttpResponse response = rest.execute(httpGet)) {
HttpEntity entity = response.getEntity();
String jsonString = EntityUtils.toString(entity);
List<T> listObjectFromJson = new ObjectMapper().readValue(jsonString, new TypeReference<List<T>>(){});
return listObjectFromJson;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
I want to just pass the class type and get objects through one method.
[
{
"id": "73cbc0b5-3dd5-49c4-97cb-6225a19122b5",
"name": "Management",
"fields": [
{
"id": "c2d740d5-4d47-42ae-b616-977b40327812",
"name": "newField1"
}
]
},
{
"id": "dd74384b-717d-4368-b0e4-3f441d5b1ffc",
"name": "IT",
"fields": []
},
{
"id": "03304335-d7d7-46ca-8075-8d5e9feb43c6",
"name": "hhh",
"fields": []
},
{
"id": "e11b4c3f-080e-490d-8ef4-ea301d551a5d",
"name": "NEWWWWW",
"fields": []
},
{
"id": "fec7eeb0-0845-49be-be14-6cdb5fcd3575",
"name": "NEWWWWW",
"fields": []
},
{
"id": "50dfea14-f30a-448c-99df-10bf01d088fa",
"name": "NEWWWWW",
"fields": []
},
{
"id": "a4a1224e-7c66-484c-ae87-dc2ecc058c36",
"name": "NEWWWWW",
"fields": []
}
]
I get this exception when my object has a relationship
Unrecognized field "fields" (class model.orm.Department), not marked as ignorable (2 known properties: "id", "name"])
at [Source: (String)"[{"id":"73cbc0b5-3dd5-49c4-97cb-6225a19122b5","name":"Management","fields":[{"id":"c2d740d5-4d47-42ae-b616-977b40327812","name":"newField1"}]},{"id":"dd74384b-717d-4368-b0e4-3f441d5b1ffc","name":"IT","fields":[]},{"id":"03304335-d7d7-46ca-8075-8d5e9feb43c6","name":"hhh","fields":[]},{"id":"e11b4c3f-080e-490d-8ef4-ea301d551a5d","name":"NEWWWWW","fields":[]},{"id":"fec7eeb0-0845-49be-be14-6cdb5fcd3575","name":"NEWWWWW","fields":[]},{"id":"50dfea14-f30a-448c-99df-10bf01d088fa","name":"NEWWWWW","fie"[truncated 84 chars]; line: 1, column: 77] (through reference chain: java.util.ArrayList[0]->model.orm.Department["fields"])
at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from
You can construct a new JavaType parametric type passing as an argument the List.class to the ObjectMapper.html#getTypeFactory method like below:
public static <T> List<T> getObjects(Class<T> c) throws IOException {
//omitted the lines before creating the mapper including the jsonstring
ObjectMapper mapper = new ObjectMapper();
JavaType type = mapper.getTypeFactory().constructParametricType(List.class, c);
return mapper.readValue(jsonString, type);
}

Returning a GeoJSON object in java

I am new to GeoJSON and im currently running into an issue that I just don't know how to do it.
Here is a snippet of what my FeatureCollection looks like
FeatureCollection fc = new FeatureCollection();
Map<String, Object> properties = new HashMap<String, Object>();
for(int i = 0; i < platforms.size(); i ++) {
Feature feature = new Feature();
Point geometry = new Point();
Dto dto = platforms.get(i);
Position position = new Position(dto.getLat(), dto.getLon());
fc.addFeature(feature);
geometry.setCoordinates(position);
feature.setGeometry(geometry);
feature.setProperties(properties);
properties.put("name", dto.getName());
properties.put("msl", dto.getMsl());
properties.put("id", dto.getId());
}
return fc.toString();
I want my output to look like this:
{
"type":"FeatureCollection"
features":[
{
"type":"Feature"
"geometry": {
"type":"Point"
"coordinates":[
-120.200000,
10.100000
]
},
"properties": {
"name": "1"
"height": "100.00"
"id": "null"
}
}
{
"type":"Feature"
"geometry": {
"type":"Point"
"coordinates\":[
-130.200000,
20.100000
] \n "
}, \n "
"properties": { "
"name": "2"
"height": "100.00"
"id": "null"
}
}
]
}
As far as I can tell, through debugging, the correct information is being placed into the feature but whenever I return the featureCollection I get this:
mil.nga.sf.geojson.FeatureCollection#366ac49b
I don't know much about geojson but it seems like I'm incorrectly returning the FeatureCollection and its printing out its name or whatever.
Simply put, how do I print the contents of a FeatureCollection?
EDIT:
This is the output that I get after implementing gson.
{
"features": [
{
"feature": {
"geometry": {
"x": 10.1,
"y": -120.2,
"z": null,
"m": null,
"geometryType": "POINT",
"hasZ": false,
"hasM": false
},
"properties": {
"msl": 100.0,
"name": "1",
"id": null
}
},
"id": null,
"bbox": null,
"foreignMembers": {}
},
{
"feature": {
"geometry": {
"x": 20.1,
"y": -130.2,
"z": null,
"m": null,
"geometryType": "POINT",
"hasZ": false,
"hasM": false
},
"properties": {
"msl": 100.0,
"name": "2",
"id": null
}
},
"id": null,
"bbox": null,
"foreignMembers": {}
}
],
"bbox": null,
"foreignMembers": {}
I am unsure what to do moving forward to get this to mirror my desired output.
Your problem is that you're calling fc.toString();, which will hit the default Object.toString() method. This will dump some classname+address/id-like String, depending on th JVM used.
Instead of calling toString(), you should use a JSON library like google gson, and add
a few lines to the bottom of your code:
final GsonBuilder gb = new GsonBuilder();
gb.setPrettyPrinting();
gb.serializeNulls();
// gb.excludeFieldsWithoutExposeAnnotation(); // maybe use for more control
final Gson gson = gb.create();
final String jsonText = gson.toJson(fc);
return jsonText;
Also consider writing a utility class that does this for you with default settings that you choose:
public class MyJsonUtil {
static public String toJSON(final Object pObject) {
final GsonBuilder gb = new GsonBuilder();
gb.setPrettyPrinting();
gb.serializeNulls();
// gb.excludeFieldsWithoutExposeAnnotation(); // maybe use for more control
final Gson gson = gb.create();
final String jsonText = gson.toJson(pObject);
return jsonText;
}
}
and then at the end of your code you simply call return MyJsonUtil.toJSON(fc).

How to implement Post API JSON with Spring?

I'm having difficulty implementing a JSON to send as a POST call in Spring.
Which is the fastest and most effective way to turn this json into a java object or a map and make the call?
below is an example of a json to send:
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"name": "edge-ws"
},
"spec": {
"selector": {
"matchLabels": {
"run": "edge-ws"
}
},
"replicas": 1,
"template": {
"metadata": {
"labels": {
"run": "edge-ws"
}
},
"spec": {
"containers": [
{
"name": "edge-ws",
"image": "server-tim:latest",
"imagePullPolicy": "Never",
"ports": [
{
"containerPort": 80
}
]
}
]
}
}
}
}
this and the second body that has a value (nodeport) that must be taken from a field entered by the user front end side.(page created in html)
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"name": "edge-ws",
"labels": {
"run": "edge-ws"
}
},
"spec": {
"type": "NodePort",
"ports": [
{
"port": 8080,
"targetPort": 80,
"nodePort": 30200,
"protocol": "TCP",
"name": "http"
}
],
"selector": {
"run": "edge-ws"
}
}
}
Both files must be sent with a single click on a button on the front end side.the first call with the first body starts and if everything is ok the second body starts
What should the class that maps objects look like? What should the controller look like instead?
They also gave me an address to call that can only be used on the machine, how can I test this call locally?
Thanks in advance!
You can use google's Gson library to convert the JsonString to Object and then use below code:
Gson gson = new Gson();
Object requestObject = gson.fromJson(jsonString, Object.class);
ResponseObject responseObject = restTemplate.postForObject(url, requestObject, ResponseObject.class);

Building JSON programmatically in java

I need to build a below JSON programmatically. But,need a elegant way to convert from Java object to JSON. so that, i can avoid string builder to build the below JSON.
I aware of that, sometimes,I have array of parameters for the specific key while building JSON.
Please share the generic way to solve that.
Please share some thoughts to this.
{
"tropo": [
{
"ask": {
"attempts": 3,
"say": [
{
"value": "Hi.",
"event": "timeout"
},
{
"value": "Hello",
"event": "nomatch:1"
},
{
"value": "Hello2",
"event": "nomatch:2"
},
{
"value": "Satheesh",
"voice": "veronica"
}
],
"choices": {
"value": "Yes(1,Yes),No(2,No)",
"mode": "ANY"
},
"voice": "veronica",
"recognizer": "en-us",
"timeout": 8,
"name": "year",
"minConfidence": 39,
"required": true
}
},
{
"on": {
"next": "https://test.app.com/WAP2/",
"event": "continue"
}
},
{
"on": {
"next": "https://test.app.com/WAP2/",
"event": "incomplete"
}
},
{
"on": {
"next": "",
"event": "hangup"
}
}
]
}
As paulsm4 said, I'd have a look at gson. It's easy to use, you can find a lot of example of how it works all over the web (official user guide).
Example:
Employee employee = new Employee();
employee.setId(1);
employee.setFirstName("Lokesh");
employee.setLastName("Gupta");
employee.setRoles(Arrays.asList("ADMIN", "MANAGER"));
Gson gson = new Gson();
System.out.println(gson.toJson(employee));
Output:
{"id":1,"firstName":"Lokesh","lastName":"Gupta","roles":["ADMIN","MANAGER"]}
From howtodoinjava.com/'s Google Gson Tutorial : Convert Java Object to / from JSON.

Categories

Resources