How read value from properties file and put into JSON file - java

I have liquibase.json file. Threa are:
"runningAs": {
"username": "Programer200"
}
I try to creat custom property:
liquibaseuser=root
Is it possible put value of liquibaseuser to liquibase.json ?

You could parse the json to a model and change the values.
import com.fasterxml.jackson.databind.ObjectMapper;
public class App
{
public static void main(String[] args)
{
// 1 read property
String property = "root";
// 2 read json
String json = "{\"username\": \"Programer200\"}";
// 3 map json to model
ObjectMapper mapper = new ObjectMapper();
MyModel jsonObject = mapper.readValue(json, MyModel.class);
// 4 change variables
jsonObject.username = property;
System.out.println(mapper.writer().writeValueAsString(jsonObject));
}
}
class MyModel
{
public String username;
}

You can utilize the below library for the data access.
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.4.0</version>
</dependency
After access the data you can modify the Json String. But firstly you require to get the data like below.
String user = JsonPath.read(json, "$.runningAs.username");
System.out.println(user);
In your quandary, it seem's like you require key and value, then you can utilize the map.

Related

Parsing a value from json response where most of the payload is redundant

To extract the name field from this json payload:
[{"name":"Estonia","topLevelDomain":[".ee"],"alpha2Code":"EE","alpha3Code":"EST","callingCodes":["372"],"capital":"Tallinn","altSpellings":["EE","Eesti","Republic of Estonia","Eesti Vabariik"],"region":"Europe","subregion":"Northern Europe","population":1315944,"latlng":[59.0,26.0],"demonym":"Estonian","area":45227.0,"gini":36.0,"timezones":["UTC+02:00"],"borders":["LVA","RUS"],"nativeName":"Eesti","numericCode":"233","currencies":[{"code":"EUR","name":"Euro","symbol":"€"}],"languages":[{"iso639_1":"et","iso639_2":"est","name":"Estonian","nativeName":"eesti"}],"translations":{"de":"Estland","es":"Estonia","fr":"Estonie","ja":"エストニア","it":"Estonia","br":"Estônia","pt":"Estónia","nl":"Estland","hr":"Estonija","fa":"استونی"},"flag":"https://restcountries.eu/data/est.svg","regionalBlocs":[{"acronym":"EU","name":"European Union","otherAcronyms":[],"otherNames":[]}],"cioc":"EST"}]
I plan to use code similar to:
#Service
public class RestService {
private final RestTemplate restTemplate;
public RestService(RestTemplateBuilder restTemplateBuilder) {
this.restTemplate = restTemplateBuilder.build();
}
public String getPostsPlainJSON() {
String url = "hhttps://restcountries.eu/rest/v2/name/eesti";
return this.restTemplate.getForObject(url, MyCustomObject.class);
}
}
MyCustomObject will contain many redundant fields that I'm not concerned with as I just wish to access the name "Estonia" for the above example. Is there an alternative method for parsing the field name rather than creating a new MyCustomObject pojo that maps to the entire JSON response?
You can Use JSONPath
public static void main(String[] args) {
String json = "[{\"name\":\"Estonia\",\"topLevelDomain\":[\".ee\"],\"alpha2Code\":\"EE\",\"alpha3Code\":\"EST\",\"callingCodes\":[\"372\"],\"capital\":\"Tallinn\",\"altSpellings\":[\"EE\",\"Eesti\",\"Republic of Estonia\",\"Eesti Vabariik\"],\"region\":\"Europe\",\"subregion\":\"Northern Europe\",\"population\":1315944,\"latlng\":[59.0,26.0],\"demonym\":\"Estonian\",\"area\":45227.0,\"gini\":36.0,\"timezones\":[\"UTC+02:00\"],\"borders\":[\"LVA\",\"RUS\"],\"nativeName\":\"Eesti\",\"numericCode\":\"233\",\"currencies\":[{\"code\":\"EUR\",\"name\":\"Euro\",\"symbol\":\"€\"}],\"languages\":[{\"iso639_1\":\"et\",\"iso639_2\":\"est\",\"name\":\"Estonian\",\"nativeName\":\"eesti\"}],\"translations\":{\"de\":\"Estland\",\"es\":\"Estonia\",\"fr\":\"Estonie\",\"ja\":\"エストニア\",\"it\":\"Estonia\",\"br\":\"Estônia\",\"pt\":\"Estónia\",\"nl\":\"Estland\",\"hr\":\"Estonija\",\"fa\":\"استونی\"},\"flag\":\"https://restcountries.eu/data/est.svg\",\"regionalBlocs\":[{\"acronym\":\"EU\",\"name\":\"European Union\",\"otherAcronyms\":[],\"otherNames\":[]}],\"cioc\":\"EST\"}]";
String jsonPath = "$.[*].name";
DocumentContext jsonContext = JsonPath.parse(json);
List<String> result = jsonContext.read(jsonPath);
System.out.println("name :: "+result.get(0));
result = jsonContext.read("$.[*].capital"); //To get Captial
System.out.println("Capital :: "+result.get(0));
}
output
name :: Estonia
Capital :: Tallinn
Maven dependency
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.4.0</version>
</dependency>

How can I introduce escape characters to my JSON mapper?

I am trying to make a simple thing using com.fasterxml.jackson.databind.ObjectMapper.
I have an object I want to translate to String.
class Car{
String color;
String brand;
//... more class info
}
It is working fine and I get my String as it should but the result looks like this:
{"color: "blue", "brand": "toyota" }
Is it possible to make it look like:
{\"color\": \"blue\", \"brand\", \"toyota\" }
I'm not sure if this breaks the JSON expected format.
I've read the docs and seems like I can use this:
ObjectMapper().factory.setCharacterEscapes(...)
But I'm not sure how to pass it or from which repo. Any ideas?
Use Jackson to generate valid JSON payload and StringEscapeUtils to escape it.
Example code:
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.text.StringEscapeUtils;
public class EscapeJsonApp {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(new Car("blue", "Toyota"));
String escapedJson = StringEscapeUtils.escapeJson(json);
System.out.println(escapedJson);
}
}
class Car {
String color;
String brand;
// getters, setters, constructor
}
Above code prints:
{\"color\":\"blue\",\"brand\":\"Toyota\"}
Maven dependency:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.8</version>
</dependency>
I am basically trying to make a mapper for an sort of inner object to
match a SNS format https://docs.aws.amazon.com/sns/latest/dg/sns-send-custom-platform-specific-payloads-mobile-devices.html
Here's one of the examples from that page:
{
"GCM":"{\"data\":{\"message\":\"Check out these awesome deals!\",\"url\":\"www.amazon.com\"}}"
}
That's a JSON object with a single field named "GCM" whose value is a string. The content of the string is another JSON object.
Let's take your Car class as an example, and assume you want to generate this JSON as your output:
{
"car": "{\"color\": \"blue\", \"brand\": \"toyota\"}"
}
First you'll need to convert your Car object to a JSON string. Then you create another JSON object and stuff the car's JSON string into a field of this outer object:
String carJson = objectMapper.writeValueAsString(myCar);
Map<String, Object> outerObject = singletonMap("car", carJson);
String finalResult = objectMapper.writeValueAsString(outerObject);
I think that you can use something like JSONObject.quote(json):
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(new Car("blue", "Toyota"));
System.out.println(JSONObject.quote(json));
Output:
"{\"color\": \"blue\", \"brand\", \"toyota\" }"

How can I construct a json with arrays and objects in java

I need a json in the following structure to pass as request body to my service.
{
"i":[
{
"a":{
"o1":"str1";
"o2":234;
}
}
]
}
I can either pass a map like
<"i[0].a.o1", "str1">
<"i[0].a.02", 345>
or pass them as string like
"i[0].a.o1"="str1"&"i[0].a.02"=345
to construct the Json.
How can I convert the map or string input to the json structure above?
Should I use inner classes for 'I' and 'A' and just use GsonUtils.getString(I)?
I agree with the answer https://stackoverflow.com/a/45367328/2735286: the Jackson library provides very nice features for serializing, deserializing objects to and from JSON.
Here is some sample code which creates the map structure you proposed, serializes it and then deserializes and checks, if the deserialized structure is the same as the original one.
public class JacksonMapperTest {
private static ObjectMapper mapper = new ObjectMapper();
public static void main(String[] args) throws IOException {
Map<String, Object> root = provideMap(); // Create map
String json = convertToJson(root); // Convert to string
System.out.println(json); // Print json
Map<String, Object> rootClone = convertToMap(json); // Convert string to map
System.out.println(root.equals(rootClone)); // Check, if the original and deserialized objects are the same.
}
private static Map<String, Object> convertToMap(String json) throws IOException {
TypeReference<HashMap<String,Object>> typeRef
= new TypeReference<HashMap<String,Object>>() {};
return mapper.readValue(json, typeRef);
}
private static String convertToJson(Map<String, Object> root) throws JsonProcessingException {
return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(root);
}
private static Map<String, Object> provideMap() {
Map<String, Object> root = new HashMap<>();
List<Map<String, Object>> i = new ArrayList<>();
root.put("i", i);
Map<String, Object> element = new HashMap<>();
Map<String, Object> a = new HashMap<String, Object>() {
{
put("o1", "str1");
put("o2", 234);
}
};
i.add(element);
element.put("a", a);
return root;
}
}
If you run this code this is what you will see in the console:
{
"i" : [ {
"a" : {
"o1" : "str1",
"o2" : 234
}
} ]
}
true
If you want to used Jackson in your project, you can create a Maven project with these dependencies in the pom.xml file:
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.8.8</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.8</version>
</dependency>
For more infos on Jackson, check: https://github.com/FasterXML/jackson
perhaps you should try jackson api. believe me, it will make your life way easier.
using this api, you can guarantee that you have a valid json object. also, you can easily build your json nodes.

Jackson filtering out fields without annotations

I was trying to filter out certain fields from serialization via SimpleBeanPropertyFilter using the following (simplified) code:
public static void main(String[] args) {
ObjectMapper mapper = new ObjectMapper();
SimpleFilterProvider filterProvider = new SimpleFilterProvider().addFilter("test",
SimpleBeanPropertyFilter.filterOutAllExcept("data1"));
try {
String json = mapper.writer(filterProvider).writeValueAsString(new Data());
System.out.println(json); // output: {"data1":"value1","data2":"value2"}
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
private static class Data {
public String data1 = "value1";
public String data2 = "value2";
}
Us I use SimpleBeanPropertyFilter.filterOutAllExcept("data1")); I was expecting that the created serialized Json string contains only {"data1":"value1"}, however I get {"data1":"value1","data2":"value2"}.
How to create a temporary writer that respects the specified filter (the ObjectMapper can not be re-configured in my case).
Note: Because of the usage scenario in my application I can only accept answers that do not use Jackson annotations.
If for some reason MixIns does not suit you. You can try this approach:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setAnnotationIntrospector(new JacksonAnnotationIntrospector(){
#Override
public boolean hasIgnoreMarker(final AnnotatedMember m) {
List<String> exclusions = Arrays.asList("field1", "field2");
return exclusions.contains(m.getName())|| super.hasIgnoreMarker(m);
}
});
You would normally annotate your Data class to have the filter applied:
#JsonFilter("test")
class Data {
You have specified that you can't use annotations on the class. You could use mix-ins to avoid annotating Data class.
#JsonFilter("test")
class DataMixIn {}
Mixins have to be specified on an ObjectMapper and you specify you don't want to reconfigure that. In such a case, you can always copy the ObjectMapper with its configuration and then modify the configuration of the copy. That will not affect the original ObjectMapper used elsewhere in your code. E.g.
ObjectMapper myMapper = mapper.copy();
myMapper.addMixIn(Data.class, DataMixIn.class);
And then write with the new ObjectMapper
String json = myMapper.writer(filterProvider).writeValueAsString(new Data());
System.out.println(json); // output: {"data1":"value1"}
The example of excluding properties by name:
public Class User {
private String name = "abc";
private Integer age = 1;
//getters
}
#JsonFilter("dynamicFilter")
public class DynamicMixIn {
}
User user = new User();
String[] propertiesToExclude = {"name"};
ObjectMapper mapper = new ObjectMapper()
.addMixIn(Object.class, DynamicMixIn.class);
FilterProvider filterProvider = new SimpleFilterProvider()
.addFilter("dynamicFilter", SimpleBeanPropertyFilter.filterOutAllExcept(propertiesToExclude));
mapper.setFilterProvider(filterProvider);
mapper.writeValueAsString(user); // {"name":"abc"}
You can instead of DynamicMixIn create MixInByPropName
#JsonIgnoreProperties(value = {"age"})
public class MixInByPropName {
}
ObjectMapper mapper = new ObjectMapper()
.addMixIn(Object.class, MixInByPropName.class);
mapper.writeValueAsString(user); // {"name":"abc"}
Note: If you want exclude property only for User you can change parameter Object.class of method addMixIn to User.class
Excluding properties by type you can create MixInByType
#JsonIgnoreType
public class MixInByType {
}
ObjectMapper mapper = new ObjectMapper()
.addMixIn(Integer.class, MixInByType.class);
mapper.writeValueAsString(user); // {"name":"abc"}
It seems you have to add an annotation which indicts which filter to use when doing the serialization to the bean class if you want the filter to work:
#JsonFilter("test")
public class Data {
public String data1 = "value1";
public String data2 = "value2";
}
EDIT
The OP has just added a note that just take the answer that not using a bean animation, then if the field you want to export is very less amount, you can just retrieve that data and build a Map of List yourself, there seems no other way to do that.
Map<String, Object> map = new HashMap<String, Object>();
map.put("data1", obj.getData1());
...
// do the serilization on the map object just created.
If you want to exclude specific field and kept the most field, maybe you could do that with reflect. Following is a method I have written to transfer a bean to a map you could change the code to meet your own needs:
protected Map<String, Object> transBean2Map(Object beanObj){
if(beanObj == null){
return null;
}
Map<String, Object> map = new HashMap<String, Object>();
try {
BeanInfo beanInfo = Introspector.getBeanInfo(beanObj.getClass());
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor property : propertyDescriptors) {
String key = property.getName();
if (!key.equals("class")
&& !key.endsWith("Entity")
&& !key.endsWith("Entities")
&& !key.endsWith("LazyInitializer")
&& !key.equals("handler")) {
Method getter = property.getReadMethod();
if(key.endsWith("List")){
Annotation[] annotations = getter.getAnnotations();
for(Annotation annotation : annotations){
if(annotation instanceof javax.persistence.OneToMany){
if(((javax.persistence.OneToMany)annotation).fetch().equals(FetchType.EAGER)){
List entityList = (List) getter.invoke(beanObj);
List<Map<String, Object>> dataList = new ArrayList<>();
for(Object childEntity: entityList){
dataList.add(transBean2Map(childEntity));
}
map.put(key,dataList);
}
}
}
continue;
}
Object value = getter.invoke(beanObj);
map.put(key, value);
}
}
} catch (Exception e) {
Logger.getAnonymousLogger().log(Level.SEVERE,"transBean2Map Error " + e);
}
return map;
}
But I recommend you to use Google Gson as the JSON deserializer/serializer And the main reason is I hate dealing with exception stuff, it just messed up with the coding style.
And it's pretty easy to satisfy your need with taking advantage of the version control annotation on the bean class like this:
#Since(GifMiaoMacro.GSON_SENSITIVE) //mark the field as sensitive data and will not export to JSON
private boolean firstFrameStored; // won't export this field to JSON.
You can define the Macro whether to export or hide the field like this:
public static final double GSON_SENSITIVE = 2.0f;
public static final double GSON_INSENSITIVE = 1.0f;
By default, Gson will export all field that not annotated by #Since So you don't have to do anything if you do not care about the field and it just exports the field.
And if some field you are not want to export to json, ie sensitive info just add an annotation to the field. And generate json string with this:
private static Gson gsonInsensitive = new GsonBuilder()
.registerTypeAdapter(ObjectId.class,new ObjectIdSerializer()) // you can omit this line and the following line if you are not using mongodb
.registerTypeAdapter(ObjectId.class, new ObjectIdDeserializer()) //you can omit this
.setVersion(GifMiaoMacro.GSON_INSENSITIVE)
.disableHtmlEscaping()
.create();
public static String toInsensitiveJson(Object o){
return gsonInsensitive.toJson(o);
}
Then just use this:
String jsonStr = StringUtils.toInsensitiveJson(yourObj);
Since Gson is stateless, it's fine to use a static method to do your job, I have tried a lot of JSON serialize/deserialize framework with Java, but found Gson to be the sharp one both performance and handily.

Parse Json with com.fasterxml.jackson instead of org.json

I was wondering if it is possible to do this exact operation but with the jackson library.
String repo = response.toString();
JSONObject json = new JSONObject (repo);
String nameOfUser = json.getJSONObject(facebookID).getString("name");
Thank you,
Yes. Something like:
ObjectMapper mapper = new ObjectMapper(); // reuse, usually static final
JsonNode ob = mapper.readTree(response.toString()); // or from File, URL, InputStream, Reader
String nameOfUser = ob.path(facebookID).path("name").asText();
// note: '.get()' also works, but returns nulls, 'path()' safer
although even more convenient access is often done using JSON Pointer expressions, like:
String name = ob.at("/person/id").asText();
but I assume facebookID is an id from some other source.
UPDATE: as per comment below, structure you want may actually be POJO like:
public class Response {
public User facebookID;
}
public class User {
public String id;
public String email;
public String first_name;
// ... and so forth: fields and/or getter+setter
}
and then you can bind directly into class like so:
Response resp = mapper.readValue(response.toString(), Response.class);
String name = resp.facebookID.name;
So there's more than one way to do it with Jackson.

Categories

Resources