JsonParser is deprecated - spring

Getting deprecated message for JsonParser for Spring Boot app,
JsonObject jsonObject = new JsonParser().parse(result).getAsJsonObject();
What is the alternative?

Based on the javadoc for Gson 2.8.6
No need to instantiate this class, use the static methods instead.
and following are the alternatives to be used.
// jsonString is of type java.lang.String
JsonObject jsonObject = JsonParser.parseString​(jsonString).getAsJsonObject();
// reader is of type java.io.Reader
JsonObject jsonObject = JsonParser.parseReader​(reader).getAsJsonObject();
// jsonReader is of type com.google.gson.stream.JsonReader
JsonObject jsonObject = JsonParser.parseReader​(jsonReader).getAsJsonObject();
Example
import static org.junit.Assert.assertTrue;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
public class Test {
public static void main(String[] args) {
String jsonString = "{ \"name\":\"John\"}";
JsonObject jsonObjectAlt = JsonParser.parseString(jsonString).getAsJsonObject();
// Shows deprecated warning for new JsonParser() and parse(jsonString)
JsonObject jsonObject = new JsonParser().parse(jsonString).getAsJsonObject();
assertTrue(jsonObjectAlt.equals(jsonObject));
}
}

new GsonBuilder().setPrettyPrinting().create().toJson(new JSONParser(jsonString).parse());

Related

Loading value from json upon start up application

I want to load the values from json file upon the Spring Boot Application is started.
My code for the Configuration File is like the below:
#Configuration
#Getter
public class FedexAPIConfig {
private final static String JSON_FILE = "/static/config/fedex-api-credentials.json";
private final boolean IS_PRODUCTION = false;
private FedexAPICred apiCredentials;
public FedexAPIConfig() {
try (InputStream in = getClass().getResourceAsStream(JSON_FILE);
BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) {
JSONObject json = new JSONObject();
// this.apiCredentials = new JSONObject(new JSONTokener(reader));
if (IS_PRODUCTION) {
json = new JSONObject(new JSONTokener(reader)).getJSONObject("production");
} else {
json = new JSONObject(new JSONTokener(reader)).getJSONObject("test");
}
System.out.println(json.toString());
this.apiCredentials = FedexAPICred.builder()
.url(json.optString("url"))
.apiKey(json.optString("api_key"))
.secretKey(json.optString("secret_key"))
.build();
} catch (FileNotFoundException fnfe) {
fnfe.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
and with this, when the application is in progress of startup, values are successfully printed on the console.Startup console log
When I tried to call this value from other ordinary class, like the below:, it brings nothing but just throws NullPointerException... What are my faults and what shall I do?
public class FedexOAuthTokenManager extends OAuthToken {
private static final String VALIDATE_TOKEN_URL = "/oauth/token";
private static final String GRANT_TYPE_CLIENT = "client_credentials";
private static final String GRANT_TYPE_CSP = "csp_credentials";
#Autowired
private FedexAPIConfig fedexApiConfig;
#Autowired
private Token token;
#Override
public void validateToken() {
// This is the part where "fedexApiConfig" is null.
FedexAPICred fedexApiCred = fedexApiConfig.getApiCredentials();
Response response = null;
try {
RequestBody body = new FormBody.Builder()
.add("grant_type", GRANT_TYPE_CLIENT)
.add("client_id", fedexApiCred.getApiKey())
.add("client_secret", fedexApiCred.getSecretKey())
.build();
response = new HttpClient().post(fedexApiCred.getUrl() + VALIDATE_TOKEN_URL, body);
if (response.code() == 200) {
JSONObject json = new JSONObject(response.body().string());
token.setAccessToken(json.optString("access_token"));
token.setTokenType(json.optString("token_type"));
token.setExpiredIn(json.optInt("expires_in"));
token.setExpiredDateTime(LocalDateTime.now().plusSeconds(json.optInt("expires_in")));
token.setScope(json.optString("scope"));
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
fedexApiConfg is null even though I autowired it in prior to call.
And this FedexOAuthTokenManager is called from other #Component class by new FedexOAuthTokenManager()
Did you try like below?
Step 1: Create one Configuration class like below
public class DemoConfig implements ApplicationListener<ApplicationPreparedEvent> {
#Override
public void onApplicationEvent(ApplicationPreparedEvent event) {
//Load the values from the JSON file and populate the application
//properties dynamically
ConfigurableEnvironment environment = event.getApplicationContext().getEnvironment();
Properties props = new Properties();
props.put("spring.datasource.url", "<my value>");
//Add more properties
environment.getPropertySources().addFirst(new PropertiesPropertySource("myProps", props));
}
To listen to a context event, a bean should implement the ApplicationListener interface which has just one method onApplicationEvent().The ApplicationPreparedEvent is invoked very early in the lifecycle of the application
Step 2: Customize in src/main/resources/META-INF/spring.factories
org.springframework.context.ApplicationListener=com.example.demo.DemoConfig
Step 3: #Value in spring boot is commonly used to inject the configuration values into the spring boot application. Access the properties as per your wish.
#Value("${spring.datasource.url}")
private String valueFromJSon;
Try this sample first in your local machine and then modify your changes accordingly.
Refer - https://www.baeldung.com/spring-value-annotation
Refer - https://www.knowledgefactory.net/2021/02/aws-secret-manager-service-as.html

Client side code for multipart REST operation

Hi I need to consume a REST operation which accepts a xml payload and a pdf file. Basically a JAXB object is converted to xml string and uploaded in a xml file. So in a multipart request, a xml file and pdf file are uploaded.
The REST operation server side code is as follows:
server side:
public class CompanyType extends MediaType {
public final static final XML_STRING = "applicaiton/company+xml";
}
#POST
#Path("/upload")
#Consumes("multipart/mixed")
#Produces(CompanyType.XML_STRING)
public UploadResponseObject upload(MultiPart multiPart){
UploadRequestObject req = multiPart.getBodyParts().get(0).getEntityAs(UploadRequestObject.class);
BodyPartEntity bpe = (BodyPartEntity) multiPart.getBodyParts().get(1).getEntity();
byte[] pdfBytes = IOUtils.toByteArray(bpe.getInputStream());
....
....
}
client side code to consume REST operation:
#Autowired
private RestTemplate rt;
public UploadResponseObject callMultipartUploadOperation(UploadRequestObject req, java.io.File target) throws Exception {
String url = "http://<host-name>:<port>/service-name/upload");
MultiValueMap<String, Object> mv = new LinkedMultiValueMap<String, Object>();
this.rt = new RestTemplate();
this.rt.setMessageConverters(getMessageConverter());
String id = <random number generated from 1 to 50000>;
// Add xml entity
org.springframework.http.HttpHeaders xmlFileHeaders = new org.springframework.http.HttpHeaders();
xmlFileHeaders.add(MeditType.CONTENT_TYPE, "applicaiton/company+xml");
HttpEntity<String> xmlFile = new HttpEntity<String>(createXMLString(req), xmlFileHeaders);
mv.add(id + ".xml", xmlFile);
// Add pdf file
org.springframework.http.HttpHeaders fileHeaders = new org.springframework.http.HttpHeaders();
fileHeaders.add(MediaType.CONTENT_TYPE, "application/pdf");
FileSystemResource fsr = new FileSystemResource(target);
HttpEntity<FileSystemResource> fileEntity = new HttpEntity<FileSystemResource>(
fsr, fileHeaders);
String filename = target.getName();
mv.add(filename, fileEntity);
HttpEntity<UploadRequestObject> ereq = new HttpEntity<UploadRequestObject>(req, getRequestHeaders());
ResponseEntity<UploadResponseObject> res= this.restTemplate.postForEntity(url, ereq, UploadResponseObject.class);
return res.getBody();
}
private List<HttpMessageConverter<?>> getMessageConverter() {
List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
jaxb2Marshaller.setClassesToBeBound(UploadResponseObject.class);
MarshallingHttpMessageConverter mhmc = new MarshallingHttpMessageConverter(jaxb2Marshaller);
List<org.springframework.http.MediaType> supportedMediaTypes = new ArrayList<org.springframework.http.MediaType>();
supportedMediaTypes.add(new org.springframework.http.MediaType("application", "company+xml"));
mhmc.setSupportedMediaTypes(supportedMediaTypes);
messageConverters.add(mhmc);
// Add Form and Part converters
FormHttpMessageConverter fmc = new FormHttpMessageConverter();
fmc.addPartConverter(new Jaxb2RootElementHttpMessageConverter());
messageConverters.add(fmc);
return messageConverters;
}
When the below line is executed from client code,
ResponseEntity<UploadResponseObject> res= this.rt.postForEntity(url, ereq, UploadResponseObject.class);
the following exception is thrown
org.springframework.web.client.RestClientException: Could not write request: no suitable HttpMessageConverter
found for request
type [org..types.UploadRequestObject]
and content type [application/company+xml]
Please advise the changes to make the client side code work.
After much trial and error, was able to find the solution for the same.
Client side code:
#Autowired
private RestTemplate rt;
public UploadResponseObject callMultipartUploadOperation(UploadRequestObject req, java.io.File target) throws Exception {
String url = "http://<host-name>:<port>/service-name/upload");
MultiValueMap<String, Object> mv = new LinkedMultiValueMap<String, Object>();
this.rt = new RestTemplate();
this.rt.setMessageConverters(getMessageConverter());
String id = <random number generated from 1 to 50000>;
// Add xml entity
org.springframework.http.HttpHeaders xmlFileHeaders = new org.springframework.http.HttpHeaders();
xmlFileHeaders.add(MeditType.CONTENT_TYPE, "applicaiton/company+xml");
HttpEntity<String> xmlFile = new HttpEntity<String>(createXMLString(req), xmlFileHeaders);
mv.add(id + ".xml", xmlFile);
// Add pdf file
org.springframework.http.HttpHeaders fileHeaders = new org.springframework.http.HttpHeaders();
fileHeaders.add(MediaType.CONTENT_TYPE, "application/pdf");
FileSystemResource fsr = new FileSystemResource(target);
HttpEntity<FileSystemResource> fileEntity = new HttpEntity<FileSystemResource>(
fsr, fileHeaders);
String filename = target.getName();
mv.add(filename, fileEntity);
HttpEntity<UploadRequestObject> ereq = new HttpEntity<UploadRequestObject>(req, getRequestHeaders());
ResponseEntity<UploadResponseObject> res= this.restTemplate.postForEntity(url, ereq, UploadResponseObject.class);
return res.getBody();
}
Message converters:
private List<HttpMessageConverter<?>> getMessageConverter() {
List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
jaxb2Marshaller.setClassesToBeBound(UploadResponseObject.class);
MarshallingHttpMessageConverter mhmc = new MarshallingHttpMessageConverter(jaxb2Marshaller);
List<org.springframework.http.MediaType> supportedMediaTypes = new ArrayList<org.springframework.http.MediaType>();
supportedMediaTypes.add(new org.springframework.http.MediaType("application", "company+xml"));
supportedMediaTypes.add(new org.springframework.http.MediaType("multipart", "form-data"));
mhmc.setSupportedMediaTypes(supportedMediaTypes);
messageConverters.add(mhmc);
// Add Form and Part converters
FormHttpMessageConverter fmc = new FormHttpMessageConverter();
fmc.addPartConverter(new Jaxb2RootElementHttpMessageConverter());
fmc.addPartConverter(new ResourceHttpMessageConverter());
messageConverters.add(fmc);
return messageConverters;
}
Request headers :
private org.springframework.http.HttpHeaders getRequestHeaders(String contentType) throws Exception {
....
.....
org.springframework.http.HttpHeaders httpHeaders = new org.springframework.http.HttpHeaders();
httpHeaders.set("Accept", "applicaiton/company+xml");
httpHeaders.set("Content-Type", "multipart/form-data");
String consumer = "<AppUserId>";
httpHeaders.set("consumer", consumer);
String tmStamp= getCurrentTimeStamp();
httpHeaders.set("timestamp", tmStamp);
...
...
return httpHeaders;
}

How to serialize an Object to Map by Moshi

I want to serialize an Object to Map by Moshi.Here is my codes by Gson
public static Map<String, String> toMap(Object obj, Gson gson) {
if (gson == null) {
gson = new Gson();
}
String json = gson.toJson(obj);
Map<String, String> map = gson.fromJson(json, new TypeToken<Map<String, String>>() {
}.getType());
return map;
}
And how to write by Moshi ?
Here's one way. Check out the toJsonValue doc here.
Moshi moshi = new Moshi.Builder().build();
JsonAdapter<Object> adapter = moshi.adapter(Object.class);
Object jsonStructure = adapter.toJsonValue(obj);
Map<String, Object> jsonObject = (Map<String, Object>) jsonStructure;
If you know the type of obj, it'd be better to look up the adapter of that type, rather than of Object. (The Object JsonAdadpter has to look up the runtime type on every toJson call.
#NanoJava8 solution crashes but can be made to work with a minor change using Map instead of HashMap
Type type = Types.newParameterizedType(Map.class, String.class, String.class);
JsonAdapter<Map<String,String>> adapter = moshi.adapter(type);
Map<String,String> map = adapter.fromJson(json);
As stated by Jesse in the answer Moshi support fields as Map but not HashMap.
In Kotlin:
val type = Types.newParameterizedType(
MutableMap::class.java,
String::class.java,
String::class.java
)
val adapter: JsonAdapter<Map<String, String>> = moshi.adapter(type)
val map: Map<String, String> = adapter.fromJson(responseJson)
Type type = Types.newParameterizedType(HashMap.class, String.class, String.class);
JsonAdapter<Map<String,String>> adapter = moshi.adapter(type);
Map<String,String> map = adapter.fromJson(json);
class HashMapJsonAdapter<K, V>(
private val keyAdapter: JsonAdapter<K>,
private val valueAdapter: JsonAdapter<V>
) : JsonAdapter<HashMap<K, V>>() {
#Throws(IOException::class)
override fun toJson(writer: JsonWriter, map: HashMap<K, V>?) {
writer.beginObject()
for ((key, value) in map ?: emptyMap<K, V>()) {
if (key == null) {
throw JsonDataException("Map key is null at ${writer.path}")
}
keyAdapter.toJson(writer, key)
valueAdapter.toJson(writer, value)
}
writer.endObject()
}
#Throws(IOException::class)
override fun fromJson(reader: JsonReader): HashMap<K, V>? {
val result = linkedMapOf<K, V>()
reader.beginObject()
while (reader.hasNext()) {
val name = keyAdapter.fromJson(reader)
val value = valueAdapter.fromJson(reader)
val replaced = result.put(name!!, value!!)
if (replaced != null) {
throw JsonDataException("Map key '$name' has multiple values at path ${reader.path} : $replaced and value")
}
}
reader.endObject()
return result
}
override fun toString(): String = "JsonAdapter($keyAdapter=$valueAdapter)"
companion object
}

GridFSDBFile cannot be cast to org.springframework.web.multipart.MultipartFile

I'm coding a spring mvc webapp that uses images of type MultipartFile which i convert to byte[] and then to Inputstream and store it in MongoDB using GridFsTemplate.
Now the problem is I want to display the stored images in a webpage but whenever I try to, the database returns the image file as GridFSDBFiles and so tosses the following exception:
java.lang.ClassCastException: com.mongodb.gridfs.GridFSDBFile cannot be cast to org.springframework.web.multipart.MultipartFile
This is my DAO for storing images:
public void saveScan(Scan scan) throws IOException {
String owner = String.valueOf(scan.getPatientId());
String fileName = String.valueOf(scan.getPatientId() + "" + scan.getScanType());
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("MM/dd/YYYY HH:mm a");
String uploadTime = simpleDateFormat.format(date);
System.out.println("the scan type is " + scan.getScanType());
DBObject metaData = new BasicDBObject();
metaData.put("owner", owner);
metaData.put("fileName", fileName);
metaData.put("uploadTime", uploadTime);
byte[] scanBytes = scan.getScan().getBytes();
InputStream inputStream = new ByteArrayInputStream(scanBytes);
scanDaoImpl.SaveScan(inputStream, fileName, "image/jpeg", metaData);
}
And this is for retrieving the images:
public MultipartFile findOneScan(BigInteger patientId) {
MultipartFile multipartFile = (MultipartFile) gridFsTemplate
.findOne(new Query(Criteria.where("metadata.owner").is(patientId)));
return multipartFile;
And this is my controller for getting images
#ResponseBody
#RequestMapping(value = "/patients/{id}/scan", produces = MediaType.IMAGE_JPEG_VALUE)
public ResponseEntity<byte[]> scanImage(#PathVariable("id") BigInteger id) throws IOException {
logger.debug("scanImage() is finding Image to display");
byte[] bs = patientScanServiceImpl.findOne(id).getBytes();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.IMAGE_JPEG);
httpHeaders.setCacheControl(CacheControl.noCache().getHeaderValue());
return new ResponseEntity<byte[]>(bs, httpHeaders, HttpStatus.OK);
}
This is my thymeleaf image tag:
<span>
<img th:src="#{/patients/{patientid}/scan(patientid=${patient.id})}" width="250" height="250"/>
</span>
Now I have more insight in this, and I have finally found a solution. You cannot directly cast a gridFSDBFile straight to byte[ ]; it must first be converted to OutputStream and then byte[ ] if it must be displayed. So I allowed my DAO method to return a GridFSDBFile but in the service layer I converted the GridFSDBFile to ByteArrayOutputStream and then to byte[ ].
Now my DAO method for retrieving images is
public GridFSDBFile findOneScan(BigInteger patientId, String scanType) {
String fileName = String.valueOf(patientId + "" + scanType);
GridFSDBFile gridFSDBFile = gridFsTemplate.findOne(new Query(Criteria.where("metadata.fileName").is(fileName)));
return gridFSDBFile;
And my service layer which feeds the controller is
public byte[] findOne(BigInteger patientId, String scanType) throws IOException {
GridFSDBFile gridFSDBFile = scanRepository.findOneScan(patientId, scanType);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
gridFSDBFile.writeTo(outputStream);
byte[] bs = outputStream.toByteArray();
return bs;
}
And the whole thing works fine.

Java : Google Reverse Geocoding with jackson API

I want to get the address using the google Maps API. In my project we are using Jackson parser.
I want to know that, how can i get my expected result i.e. :-
"A10, Dhamidhar Rd, Yashkamal Society, Vasna, Ahmedabad, Gujarat 380007, India"
I want to ignore all other fields in the API. As there are too many objects in the json file.
only want to fetch :
" "formatted_address" : "A10, Dhamidhar Rd, Yashkamal Society, Vasna, Ahmedabad, Gujarat 380007, India","
http://maps.google.com/maps/api/geocode/json?latlng=23.0043673,72.5411868999996&sensor=false
Thank you
This is what I have tried
package com.example.api.batch;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.util.JSONPObject;
public class GeocodeAddressParser {
#SuppressWarnings("deprecation")
public void getLocationInfo( String lat, String lng) throws JsonProcessingException, IOException {
HttpGet httpGet = new HttpGet("http://maps.google.com/maps/api/geocode/json?latlng="+lat+","+lng+"&sensor=false");
#SuppressWarnings("resource")
HttpClient client = new DefaultHttpClient();
HttpResponse response;
StringBuilder stringBuilder = new StringBuilder();
try {
response = client.execute(httpGet);
HttpEntity entity = response.getEntity();
InputStream stream = entity.getContent();
int b;
while ((b = stream.read()) != -1) {
stringBuilder.append((char) b);
}
} catch (ClientProtocolException e) {
} catch (IOException e) {
}
ObjectMapper mapper = new ObjectMapper();
JsonNode array = mapper.readValue(stringBuilder.toString(), JsonNode.class);
JsonNode object = array.get(0);
String reportKey = object.get("results").textValue();
// logger.info("ExportController : generatesExportExcel : parameters: {}", reportKey);
// System.out.println("Map Keys:\n"+rawData.getStatus());
//
// List<GeocodeGetResult> locations = rawData.getResults();
//
//
// for(int i=0; i < locations.size(); i++){
// GeocodeGetResult object = locations.get(i);
// System.out.println(object);
// }
// for(int i=0; i < locations.size(); i++){
// SourceLocation object = locations.get(i);
// //System.out.println(object.getClass().getName()+" "+object);
// SourceLocation converted = convertSourceLocation(object);
// System.out.println(converted);
// toBeInserted.add(converted);
// }
// JSONPObject jsonObject = new JSONPObject();
// try {
// // ObjectNode node = mapper.createObjectNode();
// JsonNode actualObj = mapper.readTree(stringBuilder.toString());
// // jsonObject = new JSONObject();
// } catch (JsonParseException e) {
// e.printStackTrace();
// }
// return mapper;
}
public static void main(String[] args) throws JsonProcessingException, IOException{
GeocodeAddressParser ref = new GeocodeAddressParser();
ref.getLocationInfo("23.0043673","72.5411868999996");
// ObjectMapper location;
// String location_string;
// try {
// //Get JSON Array called "results" and then get the 0th complete object as JSON
// location = ret.getJSONArray("results").getJSONObject(0);
// // Get the value of the attribute whose name is "formatted_string"
// location_string = location.getString("formatted_address");
// Log.d("test", "formattted address:" + location_string);
// } catch (JSONException e1) {
// e1.printStackTrace();
//
// }
}
}
Change your getLocationInfo method and replace the following part.
ObjectMapper mapper = new ObjectMapper();
JsonNode array = mapper.readValue(stringBuilder.toString(), JsonNode.class);
JsonNode object = array.get("results").get(0);
String reportKey = object.get("formatted_address").textValue();
System.out.println(reportKey);
In your given code,
JsonNode object = array.get(0);
This will return null(object contains null), because the result from the api link will return a object not an array. So, there is no 0 element here.

Resources