I have an API :
#RequestMapping(value = "/area/create",
method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public ResponseEntity<AreaEntry> createNewAreaEntry(
#RequestBody AreaRequestDto areaRequestDto) throws ServiceException {
UserContextHolder.setCustomer(areaRequestDto.getAreaEntry().getHost());
UserContextHolder.setSsoId(areaRequestDto.getUser());
AreaEntry newAreaEntryDto = service.createNewAreaEntry(areaRequestDto.getAreaEntry());
System.out.println("The area entries" + areaRequestDto.getUser()
+ " " + " "
+ areaRequestDto.getAreaEntry().getName()
+ " "
+ areaRequestDto.getAreaEntry().getCode() + " deugging");
System.out.println("the new area entry dto is" + newAreaEntryDto);
return new ResponseEntity<AreaEntry>(newAreaEntryDto, HttpStatus.OK);
I need to write a JUnit:
private List<String> getInvalidAreas(String areas) throws Exception {
ResultActions actions = mockMvc.perform(get("/area/create").param("cities", areas));
}
Where I need to pass the class arearequest dto in params
How do i do it?
You can simply pass json string, it will automatically deserialize and convert to DTO.
Or you can create utility method that convert your dto object to json and pass it as request body.
public String asJsonString(final Object obj) throws JsonProcessingException {
final ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
return mapper.writeValueAsString(obj);
}
Related
I have a service class which transforms JSON from one pattern to other using DynamoDB.
This class have various methods to manipulate JSON fields, as shown below. I have to write JUnit
tests on this code using Mockito.
The convertToProviderJson method transform one JSON which is coming from 3rd party, to a predefined template and following methods are manipulating details present on the transformed JSON.
I am new to JUnit & Mockito, how shall I proceed?
```
#Service
public class ServiceClass {
public String convertToProviderJson(String consumerString, String providerTemplateJson)
throws JsonProcessingException {
//create ObjectMapper instance
ObjectMapper objectMapper = new ObjectMapper();
//convert json file to map
String currentFieldName = "";
String currentTemplateKey = "";
boolean templateMatchError = false;
Map<?, ?> providerMap;
Map<String, Object> providerOutputMap = new LinkedHashMap<>();
System.out.println("Provider JSON");
if(!UtilityClass.isJSONValid(consumerString)) {
throw new MalformedJsonException("Incorrect Consumer Input JSON.");
}
if(!UtilityClass.isJSONValid(providerTemplateJson)) {
throw new MalformedJsonException("Incorrect Provider Template JSON.");
}
try {
JSONObject consumerJson = new JSONObject(consumerString);
providerMap = objectMapper.readValue(providerTemplateJson, Map.class);
//iterate over Provider Template map.
for (Map.Entry<?, ?> entry : providerMap.entrySet()) {
String key = (String) entry.getKey();
currentTemplateKey = key;
String value = (String) entry.getValue();
Pattern p = Pattern.compile(TransformationConstants.TEMPLATE_FUNCTION_REGEX);
Matcher matcher = p.matcher((CharSequence) entry.getValue());
if (matcher.matches()) {
String[] splitString = value.split(LEFT_ROUND_BRACKET);
String functionName = splitString[0];
String fieldName = splitString[1].split(RIGHT_ROUND_BRACKET)[0];
currentFieldName = fieldName;
Object fieldValue = invokeFunction(consumerJson, functionName, fieldName);
providerOutputMap.put(key, fieldValue);
} else {
templateMatchError = true;
break;
}
}
} catch(JsonEOFException e) {
throw new MalformedJsonException("Incorrect Provider Template JSON.");
} catch (Exception e) {
throw new MalformedJsonException("Field '" + currentFieldName + "' missing in input json.");
}
if(templateMatchError) {
throw new MalformedJsonException("Value for Field '" + currentTemplateKey
+ "' in template JSON is not in correct format.");
}
String outputJson = objectMapper.writeValueAsString(providerOutputMap);
System.out.println("Provider JSON: " + outputJson);
return outputJson;
}
private Object invokeFunction(JSONObject consumerJson, String functionName, String fieldName)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
TransformationService obj = new TransformationService();
Method method;
method = obj.getClass().getMethod(functionName, JSONObject.class, String.class);
return method.invoke(obj, consumerJson, fieldName);
}
public Object getField(JSONObject jsonObject, String fieldName) throws JSONException {
if(jsonObject.has(fieldName)) {
return jsonObject.get(fieldName);
}
throw new MalformedJsonException("Field '" + fieldName + "' missing in input json.");
}
}
I have tried to write Unit test on getField() method after going through some articles. Here's my code, I know its wrong, how shall I proceed?
#Test
public void hasFieldTest() {
JSONObject obj = new JSONObject();
obj.put("id", "1");
obj.put("name", "divyanka");
when(((Object) transformationMock.getField(jsonObjmock, "name")).thenReturn(objectMock);
JSONAssert.assertEquals("{id:1}", obj, 'strict':false);
}
To test (the getField method of) ServiceClass, i would approach like:
import static org.junit.jupiter.api.Assertions.assertThrows;
// ...
class ServiceClassTest {
//Object/Class under test:
private ServiceClass testee = new ServiceClass(); // create new or "obtain somewhere" (like #Autowired in Spring testing...)
//... test all methods, lines:
#Test
public void testGetFieldOK() {
// prepare "good" object:
JSONObject obj = new JSONObject();
obj.put("foo", "bar");
// TEST/invoke (!):
Object result = testee.getField(obj, "foo");
// assert (with your assertion framework/style):
// result is not null AND result == "bar"
// done!
}
#Test
public void testGetFieldException() {
// prepare "bad" object:
JSONObject obj = new JSONObject();
// Test/Expect exception -> https://stackoverflow.com/a/40268447/592355 ->:
MalformedJsonException thrown = assertThrows(
MalformedJsonException.class,
() -> testee.getField(obj, "foo"),
"Expected getField(obj, \"foo\") to throw, but it didn't"
);
//assert on exception (message):
assertTrue(thrown.getMessage().contains("Field 'foo' missing in input json."));
}
//create more tests like that... (-> coverage),
//.. WHEN real parameters, associated objects and class (invocations) are not applicable, mock them!
}
Thx to: https://stackoverflow.com/a/40268447/592355
And to summarize the main topics:
test a (as) real (as possible) object.
(try to) achieve coverage.
prefer "real implementations" to mocks, and use them only when real implementation is not applicable/too costly. (interfaces, external code/systems, ... internal code/systems, which "wiring" is too costly/not applicable and is covered by other tests.)
So in your code: ObjectMapper and TransformationService look like possible mocking candidates, but it is not worth, since they are created locally (in the methods to test).
UtilityClass could also be (power) mocked, but is it worth!?? :-)
In case UtilityClass would be an (external) productive (chargeable) API, you might want to mock it.
I want to deserialize a json into
Map<String, Map<String, String>
This is the json structure that i want to convert.
{
"filetype": {
"cell": "value"
},
"fileType2": {
"cell2": "value2"}
}
I tried creating a class with Map<String, Map<String, String> type and tried with ObjectMapper(com.fasterxml.jackson.databind.ObjectMapper) in jackson:
class MapOfMap {
Map<String, Map<String, String>> mapOfMap;
//getter and setter
}
objectMapper.readValue(
new File(this.getClass()
.getClassLoader()
.getResource("configs/sample.json").getFile()),
MapOfMap.class
)
I am getting this error:
Unrecognized field "fileType".
Is there any way to do this?
You don't have to write a wrapping class around your Map. Just tell the Mapper you want a Map:
String jsonString = "{\n" +
" \"filetype\": {\n" +
" \"cell\": \"value\"\n" +
" },\n" +
" \"fileType2\": {\n" +
" \"cell2\": \"value2\"}\n" +
" }";
Map<String, Map<String, String>> map;
ObjectMapper mapper = new ObjectMapper();
try {
map = mapper.readValue(
jsonString,
new TypeReference<Map<String, Map<String, String>>>(){}
);
System.out.println(map);
} catch (Exception e) {
e.printStackTrace();
}
It prints: {filetype={cell=value}, fileType2={cell2=value2}}, which looks like what you want.
For reference: this
jackson
to Map
public static HashMap<String,Object> jsonToMap(String json) throws IOException {
JsonFactory factory = new JsonFactory();
ObjectMapper mapper = new ObjectMapper(factory);
TypeReference<HashMap<String,Object>> typeRef = new TypeReference<HashMap<String,Object>>() {};
return mapper.readValue(json, typeRef);
}
to Object:
public static <T> T jsonToObject(String json, Class<T> clazz) throws IOException {
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(json, clazz);
}
using gson:
String json = "{\n" +
" \"filetype\": {\n" +
" \"cell\": \"value\"\n" +
" },\n" +
" \"fileType2\": {\n" +
" \"cell2\": \"value2\"\n" +
" }\n" +
" }";
Gson gson = new GsonBuilder().create();
Map map = gson.fromJson(json, Map.class); //will be a map of maps
note that gson defaults to LinkedTreeMaps (so the order of iteration of elements is preserved)
I need to read JSON from file and replace few objects.
For example, I have class User.java
public class User {
String username;
String email;
String city;
String code;
}
and JSON:
{
"variables":
{
"user":
{
"value":
{
"username": "$USERNAME",
"email": "$EMAIL",
"city": "$CITY"
}
}
}
}
I have two questions:
How can I read JSON from file? Read JSON will be send by WebClient POST API.
How can I replace $USERNAME, $EMAIL and $CITY? I won't hardcode it.
I have register form. When someone complete form, it will be replaced for $...
Firsty, I got hardcode JSON to string but I need read it from file
class JSONClass {
static String toFormat(User user) {
String jsonUserRegister = "{\n" +
" \"variables\":\n" +
" {\n" +
" \"user\": \n" +
" {\n" +
" \"value\":\n" +
" {\n" +
" \"username\": \"" + user.getUsername() + "\",\n" +
" \"email\": \"" + user.getEmail() + "\",\n" +
" \"city\": \"" + user.getCity() + "\",\n" +
" \"code\": \"" + user.getCode() + "\"\n" +
" } }\n" +
" }\n" +
"}";
return jsonUserRegister;
This can be achieved using Spring Boot to set up the backend to receive client calls. So to get Task 1a working, we need below
#RestController
public class JsonReaderController {
#Autowired
private ResourceLoader resourceLoader;
#PostMapping(value = "/read-json")
public String fileContent() throws IOException {
return new String(Files.readAllBytes(
resourceLoader.getResource("classpath:data/json- sample.json").getFile().toPath()));
}
}
Above code simply reads file content and returns as String. Note default response is Json.
Now that we have the backend done, we need Task 1b - Sending the POST request.
private String readJsonFile() throws IOException {
final OkHttpClient client = new OkHttpClient();
final String requestUrl = "http://localhost:8080/read-json";
Request request = new Request.Builder()
.url(requestUrl)
.post(RequestBody.create(JSON, ""))
.build();
try (Response response = client.newCall(request).execute()) {
//we know its not empty given scenario
return response.body().string();
}
}
readJsonFile method makes a POST request - using OkHttp to our backend bit (done in Task 1a) and returns the content of the file as json.
And for Task 2 - replacing $USERNAME, $EMAIL and $CITY with appropriate values. For this, we will use the Apache commons-text library.
public static void main(String[] args) throws IOException {
String fileContent = new ReadJsonFromFile().readJsonFile();
User user = new User("alpha", "alpha#tesrt.com", "Bristol", "alpha");
Map<String, String> substitutes = new HashMap<>();
substitutes.put("$USERNAME", user.getUsername());
substitutes.put("$EMAIL", user.getEmail());
substitutes.put("$CITY", user.getCity());
substitutes.put("$CODE", user.getCode());
StringSubstitutor stringSubstitutor = new StringSubstitutor(substitutes);
//include double quote prefix and suffix as its json wrapped
stringSubstitutor.setVariablePrefix("\"");
stringSubstitutor.setVariableSuffix("\"");
String updatedContent = stringSubstitutor.replace(fileContent);
System.out.println(updatedContent);
}
Hope this helps.
I want to map below Json data to java object of List<Map<String, String>> type.
Sample Json:
{
{
a:b,
c:d
},
{
e:f,
g:h,
i:j
},
{
h:k
}
}
Here a:b represents key-value pair. So a:b and c:d will be mapped to first map of the list and so on.
one way to do this is by building JSON tree and access each node and store the pair into the map.
Is there a better way to do this (cleaner approach)?
Here is the code to read a List<Map<String, String>> using the Jackson library, with your example data as input:
public class JsonTest {
public static void main(String[] args) throws Exception {
final String json
= "[\n"
+ " {\n"
+ " \"a\":\"b\",\n"
+ " \"c\":\"d\"\n"
+ " },\n"
+ " {\n"
+ " \"e\":\"f\",\n"
+ " \"g\":\"h\",\n"
+ " \"i\":\"j\"\n"
+ " },\n"
+ " {\n"
+ " \"h\":\"k\"\n"
+ " }\n"
+ "]"; // [{a:b,c:d},{e:f,g:h,i:j},{h:k}]
ObjectMapper mapper = new ObjectMapper();
TypeFactory factory = TypeFactory.defaultInstance();
List<Map<String, String>> list = mapper.readValue(json,factory
.constructCollectionType(List.class, factory
.constructMapType(Map.class, String.class, String.class)));
System.out.println(list.toString());
}
}
Note: I had to fix your outermost braces from {} to [], which is the correct JSON list syntax.
You can use Jackson to achieve this task through below example code
public class JacksonExample {
public static void main(String[] args) {
ObjectMapper mapper = new ObjectMapper();
try {
// Convert JSON string from file to Object
User user = mapper.readValue(new File("C:\\user.json"), User.class);
System.out.println(user);
// Convert JSON string to Object
String jsonInString = "{\"age\":33,\"messages\":[\"msg 1\",\"msg 2\"],\"name\":\"xyz\"}";
User user1 = mapper.readValue(jsonInString, User.class);
System.out.println(user1);
} catch (JsonGenerationException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
First I made few changes to your json to make it valid
{
"key":
[{
"a": "b",
"c": "d"
},
{
"e": "f",
"g": "h",
"i": "j"
},
{
"h": "k"
}]
}
Please find the below code that I have tried out :
ObjectMapper mapper = new ObjectMapper();
ObjectNode objectNode1 = mapper.createObjectNode();
Map<String, Object> i = mapper.readValue(new File("J:/temp/sample.json"), Map.class);
System.out.println(i.get("key"));
System.out.println(i.values());
Output :
//For System.out.println(i.get("key"));
[{a=b, c=d}, {e=f, g=h, i=j}, {h=k}]
//For System.out.println(i.values());
[[{a=b, c=d}, {e=f, g=h, i=j}, {h=k}]]
If the above approach helps you, Make a right decision based on your needs either i.get("key") or i.values()
Just use gson library to Json to object and object to Json
import java.lang.reflect.Type;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
Object to Json
Gson gson = new Gson();
Student obj=new Student();
String jsonInString = gson.toJson(obj);
Json To Object
Student obj = gson.fromJson(jsonInString, Student.class);
I am facing a problem , sometimes Json response returns an array of objects , sometimes object itself , how we can handle dynamically in the response class.
In the current eg :results sometimes gets an array of objects
"\"results\": " +
"[{" +
and sometimes object itself
"\"results\": " +
"{" +
Eg:
How we can handle this ?
Gson gson = new Gson();
SearchResponse response=new SearchResponse();
response= gson.fromJson("{" +
"\"completed_in\": 0.047," +
"\"max_id\": 291771567376039936," +
"\"max_id_str\": \"291771567376039936\"," +
"\"next_page\": \"?page=2&max_id=291771567376039936&q=javacodegeeks\"," +
"\"page\": 1," +
"\"query\": \"javacodegeeks\"," +
"\"refresh_url\": \"?since_id=291771567376039936&q=javacodegeeks\"," +
"\"results\": " +
"{" +
"\"created_at\": \"Thu, 17 Jan 2013 04:58:57 +0000\"," +
"\"from_user\": \"hkokko\"," +
"\"from_user_id\": 24726686," +
"\"from_user_id_str\": \"24726686\"," +
" \"from_user_name\": \"Hannu Kokko\"," +
" \"geo\": null," +
"\"id\": 291771567376039936," +
"\"id_str\": \"291771567376039936\"," +
"\"iso_language_code\": \"en\"," +
" \"metadata\": {" +
"\"result_type\": \"recent\"}," +
"\"profile_image_url\": \"hjh\"," +
"\"profile_image_url_https\": \"kkj\"," +
"\"source\": \"<a href="hj;\"," +
"\"text\": \"Continuous Deployment: Are You Afraid It Might Work? jh\"," +
"\"to_user\": null," +
"\"to_user_id\": 0," +
"\"to_user_id_str\": \"0\"," +
"\"to_user_name\": null" +
" }," +
"\"results_per_page\": 15," +
"\"since_id\": 0," +
"\"since_id_str\": \"0\"" +
"}", SearchResponse.class);
System.out.println(response.toString());
Kindly assist...
Can anyone give any suggestions by using different jars to achieve this?
i found a solution for this ,i felt to share this..The code will automatically convert ..if excepted response is arraylist in response class....then if object is coming in response then add to arraylist else if arraylist it will take the same list.
we need hook change the response bfore it calls fromJson.
public class ArrayAdapter<T> extends TypeAdapter<List<T>> {
private Class<T> adapterclass;
public ArrayAdapter(Class<T> adapterclass) {
this.adapterclass = adapterclass;
}
public List<T> read(JsonReader reader) throws IOException {
List<T> list = new ArrayList<T>();
Gson gson = new Gson();
if (reader.peek() == JsonToken.BEGIN_OBJECT) {
T inning = (T) gson.fromJson(reader, adapterclass);
list.add(inning);
} else if (reader.peek() == JsonToken.BEGIN_ARRAY) {
reader.beginArray();
while (reader.hasNext()) {
T inning = (T) gson.fromJson(reader, adapterclass);
list.add(inning);
}
reader.endArray();
} else {
reader.skipValue();
}
return list;
}
public void write(JsonWriter writer, List<T> value) throws IOException {
}
}
public class ArrayAdapterFactory implements TypeAdapterFactory {
#SuppressWarnings({ "unchecked" })
#Override
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> type) {
ArrayAdapter typeAdapter = null;
try {
if (type.getRawType() == List.class)
{
typeAdapter = new ArrayAdapter(
(Class) ((ParameterizedType) type.getType())
.getActualTypeArguments()[0]);
}
} catch (Exception e) {
e.printStackTrace();
}
return typeAdapter;
}
then just call
Gson gson = new GsonBuilder().registerTypeAdapterFactory(new ArrayAdapterFactory()).create();
SearchResponse response;
esponse= gson.fromJson("your json string", SearchResponse.class)
You would need to write a custom deserializer that checks the type of results in the JSON then acts accordingly.
Your POJO will contain an array for results and if your incoming JSON only has a single object you'll need to fix that. One way is to modify the JSON then deserialize it:
class SearchResponseDeserializer implements JsonDeserializer<SearchResponse> {
public SearchResponse deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
if (json.getAsJsonObject().get("results").isJsonObject()) {
//modify JSON: change results to be an array
// ...
}
return new Gson().fromJson(json, SearchResults.class);
}
}
Or, fix the server, of course. It should always be returning an array to avoid this issue.