I have a ArrayNode like this names "results":
[{
"subjectName": "Eclipse",
"code": "EC1",
"states": [
{
"subjectName": "LunorEx1",
"code":"E1"
},
{
"subjectName": "LunorEx2",
"code":"E2"
},
{
"subjectName": "Expus LunorEx3 ",
"code":"E6"
}]
},
{
"subjectName": "Lasena",
"code": "LS1",
"states": [
{
"subjectName": "SunorEx1",
"code":"S1"
},
{
"subjectName": "SunorEx2",
"code":"S2"
}]
}, {
"subjectName": "Gilesh",
"code": "GL2",
"states": [ ]
}]
this variable is public.
Using Java 8, I want to be able to check if exists for example a subjectName equals to "Eclipse" and code equals to "EC1", if this exists then I want to search inside its json states and find a state that has, for example, a subjectName equals to "LunorEx1" and code "E1", if all these are found I want to return true
private static boolean subjectValidation( String parentSubjectName, String parentCode, String childSubjectName, String childCode){
boolean valid = false;
try {
JsonNode subjectData = StreamSupport.stream(results.spliterator(), true)
.filter(c -> c.get("subjectName").asText().equals(parentSubjectName) &&
c.get("code").asText().equals(parentCode) )
.collect(Collectors.toList()).get(0);
valid = StreamSupport.stream(subjectData.get("states").spliterator(), true)
.anyMatch(k -> k.get("states").get("subjectName").asText().equals(childSubjectName) &&
k.get("states").get("code").asText().equals(childCode));
} catch (Exception e) {
}
return valid;
}
I want to optimize this cause I have several JSON arrays with the same structure and I do several similar checks ... . and to handle when the fist stream return nothing.
Can someone help me, to give some advice on how can I do this better?
I thought it could look like this:
private static boolean subjectValidation(String parentSubjectName, String parentCode, String childSubjectName,
String childCode) {
boolean valid = false;
try {
Optional<JsonNode> subjectData = StreamSupport.stream(results.spliterator(), true)
.filter(c -> exists(c, "subjectName", parentSubjectName) && exists(c, "code", parentCode))
.findFirst();
if (subjectData.isPresent()) {
valid = StreamSupport.stream(subjectData.get().get("states").spliterator(), true)
.anyMatch(k -> exists(k.get("states"), "subjectName", childSubjectName)
&& exists(k.get("states"), "code", childCode));
}
} catch (Exception e) {
}
return valid;
}
private static boolean exists(JsonNode node, String nodeName, String value) {
return node.get(nodeName).asText().equals(value);
}
I wanted to take into account that subjectName and code are not unique.
private static boolean subjectValidation(String parentSubjectName, String parentCode, String childSubjectName, String childCode) {
try {
return StreamSupport.stream(results.spliterator(), true)
.filter(c -> hasSubject(c, parentSubjectName) && hasCode(c, parentCode))
.flatmap(s -> StreamSupport.stream(s.get("states").spliterator(), true)
.map(k -> k.get("states"))
.anyMatch(k -> hasSubject(k, childSubjectName) && hasCode(k, childCode));
} catch (Exception e) {
return false;
}
}
private static boolean hasSubject(JsonNode node, String value) {
return fieldHasValue(node, "subjectName", value);
}
private static boolean hasCode(JsonNode node, String value) {
return fieldHasValue(node, "code", value);
}
private static boolean fieldHasValue(JsonNode node, String field, String value) {
return node.get(field).asText().equals(value);
}
There should probably be better exception handling but it should work.
If you want to even further generify this I would make a function which lets you make these checks on the fly simply based on setting variables for "code", "subjectname" and "states"
Related
This is my list in which I am sending itemIds for which I am fetching data and returning in an arraylist , now my requirement is if name exists and datas value is data then only show the list , else remove that object from the list, And this is I am trying to do and it is very much possible that in particular object , name and datas key might not exist in that case I am getting error such as but I dont want this error I want to return data in condition is fulfilled if no object key exists then return empty list .
{
"statusCode": 400,
"status": "Failed",
"message": "Error : Cannot invoke \"String.equals(Object)\" because \"datas\" is null",
"data": null,
"success": false
}
Code for fetching list :-
#Override
public List<Item> getcollectionfromapi(List<String> itemids) throws Exception {
List<Item> itemCollection = itemRepository.findById(itemids);
ArrayList<Item> arrayList = new ArrayList<>();
for (int i = 0; i < itemCollection.size(); i++) {
String name = itemCollection.get(i).getProduct().getName();
String datas = itemCollection.get(i).getData();
boolean equalsIgnoreCase = datas.equals("Data");
if (name.length() > 0 && equalsIgnoreCase == true) {
arrayList.addAll(itemCollection);
} else {
itemCollection.remove(i);
arrayList.addAll(itemCollection);
}
}
return arrayList;
}
sample JsonList
[
{
"id": "1",
"datas": "data",
"product": {
"name": "Transport",
"value":"1"
}
},
{
"id": "2",
"product": {
"value":"2"
}
},
{
"id": "1",
"datas": "Data",
"product": {
"name": "Transport",
"value":"3"
}
}
]
After applying Condition it should return
[
{
"id": "1",
"datas": "data",
"product": {
"name": "Transport",
"value":"1"
}
},
{
"id": "1",
"datas": "Data",
"product": {
"name": "Transport",
"value":"3"
}
}
]
public List<Item> getcollectionfromapi(List<String> itemids) throws Exception {
List<Item> itemCollection = itemRepository.findById(itemids);
ArrayList<Item> arrayList = new ArrayList<>();
for (int i = 0; i < itemCollection.size(); i++) {
String name = itemCollection.get(i).getProduct().getName();
String datas = itemCollection.get(i).getData();
//add validation for datas is not null
//add logic what to return if datas is null
//boolean equalsIgnoreCase = datas.equals("Data");
if (datas != null && name.length() < 0 && datas.equalsIgnoreCase("Data") == false) {
itemCollection.remove(i);
}
arrayList.addAll(itemCollection);
}
return arrayList;
}
There is one major problem in your code.
datas.equals("Data");
Instead of this above line you should write this way.
"Data".equals(datas).This way case you will never get null pointer exception.
Moreover you can write your code like this.
#Override
public List<Item> getcollectionfromapi(List<String> itemids) throws Exception {
List<Item> itemCollection = itemRepository.findById(itemids);
ArrayList<Item> arrayList = new ArrayList<>();
for (int i = 0; i < itemCollection.size(); i++) {
String name = itemCollection.get(i).getProduct().getName();
String datas = itemCollection.get(i).getData();
boolean equalsIgnoreCase = false;
if(datas != null)
{
equalsIgnoreCase = datas.equals("Data");
}
// if (StringUtils.isnotEmpty(name) && equalsIgnoreCase == true) // Use this condition if you have commons-lang3 jar.
if (name!=null && !("null".equals(name)) && name.length() > 0 && equalsIgnoreCase == true) {
arrayList.addAll(itemCollection);
} else {
itemCollection.remove(i);
arrayList.addAll(itemCollection);
}
}
return arrayList;
}
I am working on getting map type data stored in DynamoDB, the way I have tried so far:
use String getData() in my POJO, however, there is an issue that DynamoDBMappingException: could not unconvert attribute.
use Map<String, Object> getData() and annotated with #DynamoDBTypeConverted(converter = MapConverter.class) to retrieve the data, and also wrote a converter for it. This method also throws Exception DynamoDBMappingException: could not unconvert attribute, expected S in value.
So my question is:
is there a way to retrieve the standard JSON format data from DynamoDB by using mapper instead of DynamoJson without “N”, “S”, etc?
For instance:
"data": {
"cId":"777",
"cName":"NPR"
"isOwner":true
}
Once I get the standard JSON, I can use objectmapper to convert it to arbitrary data based on different use cases.
2. is it possible to use a map here? I found some folks create POJO for nested data, however, in my use case, the data fields vary from the different scenarios.
The converter I wrote:
public class MapConverter implements DynamoDBTypeConverter<String, Map> {
private final ObjectMapper objectMapper;
public MapConverter() {
objectMapper = new ObjectMapper();
objectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
}
#Override
public String convert(final Map map) {
if (map == null) {
return null;
}
try {
return objectMapper.writeValueAsString(map);
} catch (JsonProcessingException e) {
log.error("Hit exception while trying to convert map. {}.", map, e);
return null;
}
}
#Override
public Map unconvert(String serializedMap) {
if (serializedMap == null) {
return null;
}
try {
return objectMapper.readValue(serializedMap, Map.class);
} catch (IOException e) {
log.error("Hit exception while trying to unconvert map. {}.", serializedMap, e);
return null;
}
}
}
The data in the DynamoDB is like this:
{
"data": {
"M": {
"cId": {
"S": "777"
},
"cName": {
"S": "NPR"
},
"isOwner": {
"BOOL": true
}
}
}
}
and it may also look like
"data": {
"M": {
"globalEntityId": {
"S": "234"
},
"providerMetadata": {
"L": [
{
"M": {
"proj.123": {
"M": {
"entityId": {
"S": "s:123"
}
}
},
"PA": {
"M": {
"entityId": {
"S": "p:123"
}
}
}
}
}
]
}
}
}
I'm trying to get a list of objects AccountData from my JSON-RPC server using jsonrpc4j.
Here is code:
class AccountData {
public Integer id;
public Double accDeposit;
public Double accCredit;
public String accPerson;
public String accAddressCity;
public String accAddressStreet;
public String accAddressBuild;
public String accAddressApt;
public Date accRegDate;
public String accPersonPassport;
public String accPersonPhone;
public String accPersonEmail;
public String accComments;
public String accLogin;
public String accPassword;
}
public void initialize() {
try {
JsonRpcHttpClient client = new JsonRpcHttpClient(new URL("http://localhost:8032/api"));
try {
List<AccountData> accountData = Arrays.asList(client.invoke("getUserAccount", new Object[]{}, AccountData.class));
System.out.println("Method invoked");
if (accountData != null) {
for (AccountData data : accountData) {
System.out.println("login=" + data.accLogin);
}
}
} catch (Throwable throwable) {
throwable.printStackTrace();
}
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
And I'm getting an exception:
> com.googlecode.jsonrpc4j.HttpException: null
com.googlecode.jsonrpc4j.JsonRpcHttpClient.invoke(JsonRpcHttpClient.java:166)
com.googlecode.jsonrpc4j.JsonRpcHttpClient.invoke(JsonRpcHttpClient.java:121)
com.googlecode.jsonrpc4j.JsonRpcHttpClient.invoke(JsonRpcHttpClient.java:132)
My JSON-RPC server returns result correctly, I've tested in python/php clients. Single results (non-array) works correctly too in Java.
The JSON you posted is not valid. Try it at http://jsonlint.com/
You should use double quotes instead of single quotes and also None should be in double quotes too:
{
"id": 0,
"result": [{
"accDeposit": 100.0,
"accComments": "test account",
"accPersonPassport": "FR8382",
"accAddressStreet": "None",
"accPersonEmail": "john#johndoe.john",
"accPassword": "test",
"accPersonPhone": "+70717654321",
"id": 8,
"accPerson": "John Doe",
"accAddressCity": "test city",
"accRegDate": "2016-07-11",
"accLogin": "john",
"accCredit": 0.0,
"accAddressBuild": "1",
"accAddressApt": "18"
}],
"jsonrpc": "2.0"
}
Use AccountData[].class
`
try {
JsonRpcHttpClient client = new JsonRpcHttpClient(new URL("http://localhost:8032/api"));
try {
List<AccountData> accountData = Arrays.asList(client.invoke(
"getUserAccount",
new Object[]{},
AccountData[].class
));
System.out.println("Method invoked");
if (accountData != null) {
for (AccountData data : accountData) {
System.out.println("login=" + data.accLogin);
}
}
} catch (Throwable throwable) {
throwable.printStackTrace();
}
} catch (MalformedURLException e) {
e.printStackTrace();
}
`
I am trying deserialize the result returned from an API call. However, the result can either contain a Boolean or an array.
If the result is Boolean, the JSON content received in the response looks like:
{
"succeeded": true,
"version": 1.0
}
If the result is an array, the JSON received in the response looks like:
{
"succeeded": {
"current_page": 1,
"per_page": 100,
"results": [
{
"get_info": {
"fieldA": "4198126",
"fieldB": "2016-05-25T22:43:52Z",
"fieldC": "iws-user-cfg-proxy-beta",
"updated_at": "2016-05-25T22:43:52Z"
}
},
{
"get_info": {
"fieldA": "4551542",
"fieldB": "2016-07-27T22:26:27Z",
"fieldC": "silkRoot",
"updated_at": "2016-07-27T22:26:27Z"
}
}
]
},
"version": 1.0
}
I would like to read the value associated with the "succeeded" field. Is there a way I can handle this in the mapping class?
My current mapping class is as below:
public class ServResp {
public final static String TYPE1_EXCEPTION = "Type1Exception";
public final static String TYPE2_EXCEPTION = "Type2Exception";
public final int httpStatusCode;
public final boolan succeeded;
public final String version;
public final String exception;
public final String exceptionMessage;
private ServResp(Builder builder) {
this.httpStatusCode = builder.httpStatusCode;
this.succeeded = builder.succeeded;
this.version = builder.version;
this.exception = builder.exception;
this.exceptionMessage = builder.exceptionMessage;
}
public Builder modify() {
return new Builder(this);
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((exception == null) ? 0 : exception.hashCode());
result = prime * result + ((exceptionMessage == null) ? 0 : exceptionMessage.hashCode());
result = prime * result + httpStatusCode;
result = prime * result + (succeeded ? 17 : 19);
result = prime * result + ((version == null) ? 0 : version.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ServResp other = (ServResp) obj;
if (exception == null) {
if (other.exception != null)
return false;
} else if (!exception.equals(other.exception))
return false;
if (exceptionMessage == null) {
if (other.exceptionMessage != null)
return false;
} else if (!exceptionMessage.equals(other.exceptionMessage))
return false;
if (httpStatusCode != other.httpStatusCode)
return false;
if (succeeded != other.succeeded)
return false;
if (version == null) {
if (other.version != null)
return false;
} else if (!version.equals(other.version))
return false;
return true;
}
public static class Builder {
private int httpStatusCode;
private boolean succeeded;
private String version;
private String exception;
private String exceptionMessage;
public Builder() {
}
public Builder(ServResp other) {
this.httpStatusCode = other.httpStatusCode;
this.version = other.version;
this.exception = other.exception;
this.exceptionMessage = other.exceptionMessage;
}
public Builder setHttpStatusCode(int httpStatusCode) {
this.httpStatusCode = httpStatusCode;
return this;
}
public Builder setSucceeded(boolean succeeded) {
this.succeeded = succeeded;
return this;
}
public Builder setVersion(String version) {
this.version = version;
return this;
}
public Builder setException(String exception) {
this.exception = exception;
return this;
}
public Builder setExceptionMessage(String exceptionMessage) {
this.exceptionMessage = exceptionMessage;
return this;
}
public ServResp build() {
return new ServResp(this);
}
}}
If I execute the program the way it is, I get the below error:
Caused by: org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of java.lang.boolean out of START_OBJECT token
Is there a way to get around this?
You could try changing the type of Builder.succeeded to Object, and then add some code to read it later. This sounds like a source of future bugs, but if you don't control the API then it may be your best shot.
public class Foo {
private Object overRiddenJsonType;
public Object getOverRiddenJsonType() {
return overRiddenJsonType;
}
public void setOverRiddenJsonType(Object overRiddenJsonType) {
this.overRiddenJsonType = overRiddenJsonType;
}
}
public class FooConsumer {
public void consumeFoo(Foo foo) {
Boolean b = false;
Bar bar = null;
if (foo.getOverRiddenJsonType() instanceof Boolean) {
b = (Boolean)foo.getOverRiddenJsonType();
// Worry about an NPE from unboxing later...
} else if (foo.getOverRiddenJsonType() instanceof Bar) {
bar = (Bar)foo.getOverRiddenJsonType();
}
// ...
}
}
If, on the other hand, you do control the API, then a better solution would be to restructure your JSON such that success is always boolean, and the rest of the data is either a top-level field or a member of results:
{
"succeeded": true,
"version": 1.0,
"current_page": 1,
"per_page": 100,
"results": [
{
"get_info": {
"fieldA": "4198126",
...
}
]
}
I would suggest to generate a plain POJO for the JSON content below using the tool JSONschema2POJO.
While generating the POJO you can select Source type as JSON and Annotation style as none.
{
"succeeded": {
"current_page": 1,
"per_page": 100,
"results": [
{
"get_info": {
"fieldA": "4198126",
"fieldB": "2016-05-25T22:43:52Z",
"fieldC": "iws-user-cfg-proxy-beta",
"updated_at": "2016-05-25T22:43:52Z"
}
},
{
"get_info": {
"fieldA": "4551542",
"fieldB": "2016-07-27T22:26:27Z",
"fieldC": "silkRoot",
"updated_at": "2016-07-27T22:26:27Z"
}
}
]
}
}
Once you added the generated bean into your project, you could add this overloaded method in your mapper class:
private Succeeded succeeded;
/**
*
* #return
* The succeeded
*/
public Succeeded getSucceeded() {
return succeeded;
}
/**
*
* #param succeeded
* The succeeded
*/
public void setSucceeded(Succeeded succeeded) {
this.succeeded = succeeded;
}
During automation test run, I come across JsonObject like followin, let's call it jsonObject.
{
"434": {
"Test1": {
"id": "0001",
"Name": "John"
}
},
"435": {
"Test2": {
"id": "0002",
"Name": "John"
}
}
}
I want to retrieve JsonObject for Test1 and Test2. I can retrieve it like:
jsonObject.getJsonObject("434").getJsonObject("Test1");
jsonObject.getJsonObject("435").getJsonObject("Test2");
But values 434 and 435 are not constants. When I re-run test, this time those could be some different numbers. Hence I don't know what could be there next time instead of 434 and 435
Is there any way, I can get JsonObject of Test1 and Test2 irrespective of 434 and 435 (something like jsonObject.someMethod("Test1");)?
I'm using javax.json library.
You can use jsonObject.keys() to get an iterator of all property names in current JSON object. This will allow you to do something like this:
Iterable<String> keys = () -> jsonObject.keys();
List<JSONObject> nestedFilteredObjects = stream(keys.spliterator(), false)
.filter(key -> jsonObject.getJSONObject(key).has("Test"))
.map(key -> jsonObject.getJSONObject(key))
.collect(toList());
Of course you still need to add try-catches for the json exceptions and consider what happens when the property is not a json object (getJSONObject will throw the exception).
Something like the code below should do. Please keep in mind that I did not test it and you can adapt it more to your needs - I don't know what possible jsons you may have in your tests:
private static List<JSONObject> getNestedTestObjects(JSONObject jsonObject) {
#SuppressWarnings("Convert2MethodRef")
Iterable<String> keys = () -> jsonObject.keys();
return stream(keys.spliterator(), false)
.map(key -> object(jsonObject, key))
.filter(object -> object instanceof JSONObject)
.map(object -> (JSONObject) object)
.filter(object -> object.has("Test"))
.map(object -> object(object, "Test"))
.filter(object -> object instanceof JSONObject)
.map(object -> (JSONObject) object)
.collect(toList());
}
private static Object object(JSONObject jsonObject, String key) {
try {
return jsonObject.get(key);
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
You can retrieve your target object by passing in the key you are searching for. The method will handle traveling down to each child object to find the matching key. It will return the first match.
Also, you can retrieve all nested JSON objects at a desired depth by using a recursive routine as seen below. You choose the level and the method will add each JsonObject to a results list. The list is printed at the end.
import java.io.*;
import java.util.*;
import javax.json.*;
import javax.json.stream.JsonGenerator;
public class JsonSearchUtilities {
public static void main(String[] args) {
JsonObject jsonObj = readJson("data.json");
// Search for a JSON object by its key.
System.out.println("===================\nSearch by Key\n===================");
searchByKey(jsonObj, "Test2");
// Search for a JSON objects by depth.
System.out.println("\n===================\nSearch by Depth\n===================\n");
searchFullDepth(jsonObj);
}
// ========================================================================
// Main Routines
// ========================================================================
public static void searchByKey(JsonObject jsonObj, String key) {
JsonObject json = getJsonByKey(jsonObj, key);
String jsonStr = prettyPrint(json);
System.out.println(jsonStr);
}
public static void searchFullDepth(JsonObject jsonObj) {
JsonArray jsonArr = null;
int depth = 0;
do {
jsonArr = getNestedObjects(jsonObj, depth);
String jsonStr = prettyPrint(jsonArr);
System.out.printf("Depth = %d%n%s%s%n%n", depth, "---------", jsonStr);
depth++;
} while (jsonArr != null && !jsonArr.isEmpty());
}
// ========================================================================
// Key Search - Search by key
// ========================================================================
public static JsonObject getJsonByKey(JsonObject jsonObj, String search) {
return getJsonByKey(jsonObj, search, 10);
}
public static JsonObject getJsonByKey(JsonObject jsonObj, String search, int maxDepth) {
return getJsonByKey(jsonObj, search, maxDepth, 0);
}
/** #private Inner recursive call. */
private static JsonObject getJsonByKey(JsonObject jsonObj, String search, int maxDepth, int level) {
if (level < maxDepth && jsonObj != null) {
Object child = null;
for (String key : jsonObj.keySet()) {
child = jsonObj.get(key);
if (child instanceof JsonObject) {
if (key.equals(search)) {
return (JsonObject) child;
}
}
}
return getJsonByKey((JsonObject) child, search, maxDepth, level + 1);
}
return null;
}
// ========================================================================
// Depth Search - Search by depth
// ========================================================================
public static JsonArray getNestedObjects(JsonObject jsonObj, int depth) {
JsonArrayBuilder builder = Json.createArrayBuilder();
getNestedObjects(jsonObj, builder, depth);
return builder.build();
}
/** #private Inner recursive call. */
private static void getNestedObjects(JsonObject jsonObj, JsonArrayBuilder builder, int level) {
if (level == 0) {
builder.add(jsonObj);
}
if (jsonObj != null) {
for (String key : jsonObj.keySet()) {
Object child = jsonObj.get(key);
if (child instanceof JsonObject) {
getNestedObjects((JsonObject) child, builder, level - 1);
}
}
}
}
// ========================================================================
// Utilities - Read and write
// ========================================================================
private static InputStream getInputStream(String filename, boolean isResource) throws FileNotFoundException {
if (isResource) {
ClassLoader loader = JsonSearchUtilities.class.getClassLoader();
return loader.getResourceAsStream(filename);
} else {
return new FileInputStream(new File(filename));
}
}
public static JsonObject readJson(String filename) {
InputStream stream = null;
try {
stream = getInputStream(filename, true);
JsonReader reader = Json.createReader(stream);
return reader.readObject();
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
public static String prettyPrint(JsonStructure json) {
return jsonFormat(json, JsonGenerator.PRETTY_PRINTING);
}
public static String jsonFormat(JsonStructure json, String... options) {
StringWriter stringWriter = new StringWriter();
Map<String, Boolean> config = new HashMap<String, Boolean>();
if (options != null) {
for (String option : options) {
config.put(option, true);
}
}
JsonWriterFactory writerFactory = Json.createWriterFactory(config);
JsonWriter jsonWriter = writerFactory.createWriter(stringWriter);
jsonWriter.write(json);
jsonWriter.close();
return stringWriter.toString();
}
}
Output
===================
Search by Key
===================
{
"id":"0002",
"Name":"John"
}
===================
Search by Depth
===================
Depth = 0
---------
[
{
"434":{
"Test1":{
"id":"0001",
"Name":"John"
}
},
"435":{
"Test2":{
"id":"0002",
"Name":"John"
}
}
}
]
Depth = 1
---------
[
{
"Test1":{
"id":"0001",
"Name":"John"
}
},
{
"Test2":{
"id":"0002",
"Name":"John"
}
}
]
Depth = 2
---------
[
{
"id":"0001",
"Name":"John"
},
{
"id":"0002",
"Name":"John"
}
]
Depth = 3
---------
[
]