How to validate each of the names, ages and descriptions irrespective of json array index? It will kind of search that we need to validate on the basis of name, age and description with age is matching or not.
[
{
"Name": "Shobit",
"transactionDate": 1623049638000,
"age": "18",
"description": "My item for new collection addition into system with age 18"
},
{
"Name": "Neha",
"transactionDate": 1623049877000,
"age": "20",
"description": "My item for new collection addition into system with age 20"
}
]
You can convert your data to JSONArray and check each item as a JSONObject for example
JSONArray array = new JSONArray(data);
for(int i = 0; i < array.length() ; i++) {
JSONObject user = array.getJSONObject(i);
String name = user.getString("Name");
long transactionDate = user.getLong("transactionDate");
int age = user.getInt("age");
String description = user.getString("description");
// Validate here
}
Or move the validation to another method for example
JSONArray array = new JSONArray(data);
for(int i = 0; i < array.length() ; i++) {
JSONObject user = array.getJSONObject(i);
boolean isValidInfo = isValidateUser(user);
}
Validation method
public boolean isValidateUser(JSONObject user) {
String name = user.getString("Name");
long transactionDate = user.getLong("transactionDate");
int age = user.getInt("age");
String description = user.getString("description");
// Validate here
}
For java you can use the library "org.json"
Add in your pom.xml dependency:
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20180813</version>
</dependency>
Now you can use the next solution with java 8 :
JSONArray jsonArray = new JSONArray(yourJsonArray);
IntStream.range(0, jsonArray.length()).forEachOrdered(index -> {
// below the solution #AmrDeveloper
JSONObject user = jsonArray.getJSONObject(index);
String name = user.getString("Name");
long transactionDate = user.getLong("transactionDate");
int age = user.getInt("age");
String description = user.getString("description");
// Validate here
});
OR USE other libraries.
Example with Jackson
Add dependency:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.6.2</version>
</dependency>
Create POJO:
public class User {
private String name;
private Long transactionDate;
private Integer age;
private String description;
public User(String name, Long transactionDate, Integer age, String description) {
this.name = name;
this.transactionDate = transactionDate;
this.age = age;
this.description = description;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getTransactionDate() {
return transactionDate;
}
public void setTransactionDate(Long transactionDate) {
this.transactionDate = transactionDate;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
Create method:
public <T> Optional<List<T>> buildListObjectsFromJson(String jsonObjectsList, Class<T> clazz) {
LOGGER.info("Try to build list objects from json....");
try {
ObjectMapper objectMapper = new ObjectMapper();
List<T> objectsList = objectMapper
.readValue(jsonObjectsList, objectMapper.getTypeFactory()
.constructCollectionType(ArrayList.class, clazz));
LOGGER.info("Objects list created successfully! List size = {}", objectsList.size());
return Optional.of(objectsList);
} catch (Exception e) {
e.printStackTrace();
LOGGER.error("Can't build List objects by json: {}", jsonObjectsList);
}
return Optional.empty();
}
And create use next example:
List<User> users = buildListObjectsFromJson(yourJsonArray, User.class).orElse(new ArrayList<>());
This way you can work with this data as a collection.
Related
I have come across a situation where I have to support existing client, they are using below payload for rest api,
{
"firstName": "First name",
"secondName": "Second name",
"dateOfBirth": "01/12/2020",
"profession": "Software Developer",
"salary": 0,
**"value": "value1"**
}
but now as per requirement, they may send array for value field like below :
{
"firstName": "First name",
"secondName": "Second name",
"dateOfBirth": "01/12/2020",
"profession": "Software Developer",
"salary": 0,
**"value": ["Value1", "value2", "Value3"]**
}
Existing code uses #RequestBody to convert it to PersonDTO person, this class also contains a method called isMutliValue() & getMultiValueFor(), and these methods splits the string based on comma then decide and return values out of it. but now for this requirement, I have to made a modification to check if client is sending array in value or simple string. if it is a simple string then don't split it based on comma and simply process it but if it is an array, bring values out of it and send individual values.
public class PersonDTO {
private String firstName;
private String secondName;
// Formats output date when this DTO is passed through JSON
#JsonFormat(pattern = "dd/MM/yyyy")
// Allows dd/MM/yyyy date to be passed into GET request in JSON
#DateTimeFormat(pattern = "dd/MM/yyyy")
private Date dateOfBirth;
private String profession;
private BigDecimal salary;
private String value;
public PersonDTO(
String firstName, String secondName, Date dateOfBirth, String profession, BigDecimal salary, String value) {
this.firstName = firstName;
this.secondName = secondName;
this.dateOfBirth = dateOfBirth;
this.profession = profession;
this.salary = salary;
this.value = value;
}
public PersonDTO() {}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getSecondName() {
return secondName;
}
public void setSecondName(String secondName) {
this.secondName = secondName;
}
public Date getDateOfBirth() {
return dateOfBirth;
}
public void setDateOfBirth(Date dateOfBirth) {
this.dateOfBirth = dateOfBirth;
}
public String getProfession() {
return profession;
}
public void setProfession(String profession) {
this.profession = profession;
}
public BigDecimal getSalary() {
return salary;
}
public void setSalary(BigDecimal salary) {
this.salary = salary;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
public boolean isMultiValued() {
return value.split(",").length > 1;
}
public String[] getMultiValues() {
return value.split(",");
}
public String toString(){
return "FirstName : " + firstName +" SecondName : "+ secondName +", Value : "+ value.toString();
}
}
please help me out, how can we handle different type of values in single field of json payload.
In this case you can implement custom deserialization. so for this purpose you should define a PersonDTODeserializer that extends from JsonDeserializer and override deserialize method.
public class PersonDTODeserializer extends JsonDeserializer {
#Override
public Object deserialize(JsonParser jsonParser,
DeserializationContext deserializationContext) throws IOException {
JsonNode node = jsonParser.getCodec().readTree(jsonParser);
String name = node.get("firstName").textValue();
String secondName = node.get("secondName").textValue();
BigDecimal salary = node.get("salary").decimalValue();
String value = "";
JsonNode nodeValue = node.get("value");
if (nodeValue.isArray()) {
Iterator<JsonNode> nodeIterator = nodeValue.iterator();
List<String> values = new ArrayList<>();
while (nodeIterator.hasNext()) {
values.add( nodeIterator.next().textValue());
}
value = String.join(",",values);
} else if (nodeValue.isTextual()) {
value = nodeValue.textValue();
}
return new PersonDTO(name, secondName, salary, value);
}
}
and use it in PersonDTO class.
#JsonDeserialize(using = PersonDTODeserializer.class)
public class PersonDTO {
//other
}
Based on #Hadi J answer,
you can set the deserializer on this field only and not the whole class :
public class PersonDTO {
// ...
#JsonDeserialize(using = ValueDeserializer.class)
private String value;
// ...
}
and the Deserializer:
private static class ValueDeserializer extends JsonDeserializer<String> {
#Override
public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
if( p.isExpectedStartArrayToken() ) {
List<String> values = new ArrayList<String>( p.readValueAs(List.class) );
return String.join(",", values);
} else {
return p.getValueAsString();
}
}
}
i have problem with my list. My goal is to make a JTree from my json list. To do it i convert my json where i have my patients to list. But i cannot even display the name of mine patient. Maybe my code make my problem clearer. I would be grateful for any suggestion!
My patient class:
public class Patient {
private String name;
private String surname;
private String pesel;
public Patient(String name, String surname, String pesel) {
this.name = name;
this.surname = surname;
this.pesel = pesel;
}
public String getName(){return name;}
public void setName(String name){this.name = name;}
public String getSurname(){return surname;}
public void setSurname(String surname){this.surname = surname;}
public String getPesel(){return pesel;}
public void setPesel(String pesel){this.pesel = pesel;}
}
My patientList:
(This method works, when i am using it to convert medicine json to medicine list i have no problem)
public List<Patient> FromJsonToArray1() throws IOException {
String patientsJson = initArray("Patients.json").toString();
Gson gson = new Gson();
java.lang.reflect.Type patientsListType = new TypeToken<ArrayList<Patient>>() {}.getType();
List<Patient> patientArray = gson.fromJson(patientsJson, patientsListType);
return patientArray;
}
And this is my function to show name of mine patient.
public void jtreecreator() throws IOException {
List<Medicine> medicineList = FromJsonToArray();
List<Patient> patientList = FromJsonToArray1();
medicinesDataMethods medicinesdatamethods = new medicinesDataMethods();
DefaultMutableTreeNode root = new DefaultMutableTreeNode("Patients");
Patient c = patientList.get(0);
Medicine d = medicineList.get(0);
DefaultTreeModel treeModel = new DefaultTreeModel(root);
JTree tree = new JTree(treeModel);
JScrollPane scrollPane = new JScrollPane(tree);
JOptionPane.showMessageDialog(null,c.getSurname());
JOptionPane.showMessageDialog(null, d.getName());
}
And after call this function it display d.getName(), but c.getSurname() didnt work.
Its my json where i store my patients:
[
{
"Pesel": "1111",
"Surname": "Walker",
"Name": "Johny "
},
{
"Pesel": "11111",
"Surname": "Walker1",
"Name": "Johny1 "
}
]
After debug, i find out that my list which is created in FromJsonToArray1() has objects of patients but values of name, surname and pesel are null. :C
Issue is attribute names in class and json do not match. You can modify Patient class like
class Patient {
#SerializedName("Name")
private String name;
#SerializedName("Surname")
private String surname;
#SerializedName("Pesel")
private String pesel;
// getters and setters, constructor, etc. here
}
I have a json file like this:
{
"Student" : [
{
"name": "john",
"age": 12
}, {
"name": "jack",
"age": 20
}
]
}
and my Student class is:
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
I want to make a Student Instance with name "jack" by using json
how can I do it?
Make Another Class Students which contain List<Student>.
public class Students {
List<Student> Student;
public List<Student> getStudents() {
return Student;
}
public void setStudent(List<Student> students) {
this.Student=students;
}
}
Gson gson = new Gson();
String jsonString = "Your Json String";
Students student = gson.fromJson(jsonString, Students.class);
I use org.json.simple library when I parse JSON
Excample:
excample App.java,
excample Information.java
List<Information> parseInformationObject(JSONArray infoList) {
List<Information> in = new ArrayList<>();
infoList.forEach(emp -> {
JSONObject info = (JSONObject) emp;
String id = info.get("id").toString();
String state = info.get("state").toString();
String type = null;
if (info.get("type") != null) {
type = info.get("type").toString();
}
String host = null;
if (info.get("host") != null) {
host = info.get("host").toString();
}
long timestamp = (long) info.get("timestamp");
in.add(new Information(id, state, type, host, timestamp));
});
return in;
}
I use Java + Gson and I want serialize a special json. I want content of object instand of object.
{
"age": 26,
"email": "norman#futurestud.io",
"isDeveloper": true,
"name": "Norman",
"userAddress": {
"city": "Magdeburg",
"country": "Germany",
"houseNumber": "42A",
"street": "Main Street"
}
}
is it possible serialize to:
{
"age": 26,
"email": "norman#futurestud.io",
"isDeveloper": true,
"name": "Norman",
"city": "Magdeburg",
"country": "Germany",
"houseNumber": "42A",
"street": "Main Street"
}
I try use this code but wrong:
#Expose
private final String age;
...
#Expose
#JsonAdapter(UserAddressSerializer.class)
private final UserAddress userAddress;
...
public class UserAddressSerializer implements JsonSerializer<UserAddress > {
#Override
public JsonElement serialize(UserAddress src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject result = new JsonObject();
result.add("name", new JsonPrimitive(src.getName()));
result.add("city", new JsonPrimitive(src.getCity()));
result.add("country", new JsonPrimitive(src.getCountry()));
result.add("houseNumber", new JsonPrimitive(src.getHouseNumber()));
result.add("street", new JsonPrimitive(src.getStreet()));
return result;
}
}
JSON trees are what you are looking for.
But at least one caveat here is sharing same-named property names among different objects.
Suppose you have the following data classes:
final class User {
final String email;
final String name;
final int age;
final boolean isDeveloper;
User(final String email, final int age, final String name, final boolean isDeveloper) {
this.age = age;
this.email = email;
this.isDeveloper = isDeveloper;
this.name = name;
}
#Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("email", email)
.add("name", name)
.add("age", age)
.add("isDeveloper", isDeveloper)
.toString();
}
}
final class UserAddress {
final String country;
final String city;
final String street;
final String houseNumber;
UserAddress(final String country, final String city, final String street, final String houseNumber) {
this.country = country;
this.city = city;
this.street = street;
this.houseNumber = houseNumber;
}
#Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("country", country)
.add("city", city)
.add("street", street)
.add("houseNumber", houseNumber)
.toString();
}
}
Now you can have an utility method to serialize multiple objects into a single JsonObject instance.
Also, you can easily have a deserialization counter-part that can deserialize multiple objects from a JsonObject instance.
For example:
final class JsonObjects {
private JsonObjects() {
}
#SafeVarargs
static JsonObject combine(final Gson gson, final Map.Entry<Object, ? extends Type>... objectAndTypeEntries) {
return Stream.of(objectAndTypeEntries)
// Each element should be serialized to a JsonElement
.map(e -> gson.toJsonTree(e.getKey(), e.getValue()))
// That must be a JSON object
.map(JsonElement::getAsJsonObject)
// And now we can collect a stream of JsonObject instances into a super-object
.collect(Collector.of(
JsonObject::new, // We'll collect into a new JsonObject instance, this is the accumulator
JsonObjects::mergeInto, // Merge each consecutive JsonObject instance into the accumulator
JsonObjects::mergeInto, // Or even combine multiple accumulators
Function.identity() // And just return the accumulator
));
}
static List<?> split(final Gson gson, final JsonObject jsonObject, final Type... types) {
return Stream.of(types)
// Each element should be deserialized from the JsonObject by a type
.map(type -> gson.fromJson(jsonObject, type))
// And just collect all the deserialized objects to a list
.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
}
private static JsonObject mergeInto(final JsonObject to, final JsonObject from) {
for ( final Map.Entry<String, JsonElement> e : from.entrySet() ) {
to.add(e.getKey(), e.getValue());
}
return to;
}
}
Example of use:
final User beforeUser = new User("norman#localhost", 26, "Norman", true);
System.out.println("BEFORE User: " + beforeUser);
final UserAddress beforeUserAddress = new UserAddress("Germany", "Magdeburg", "Main Street", "42A");
System.out.println("BEFORE User address: " + beforeUserAddress);
final JsonObject jsonObject = JsonObjects.combine(
gson,
new AbstractMap.SimpleImmutableEntry<>(beforeUser, User.class),
new AbstractMap.SimpleImmutableEntry<>(beforeUserAddress, UserAddress.class)
);
System.out.println("JSON: " + jsonObject);
final List<?> objects = JsonObjects.split(gson, jsonObject, User.class, UserAddress.class);
final User afterUser = (User) objects.get(0);
System.out.println("AFTER User: " + afterUser);
final UserAddress afterUserAddress = (UserAddress) objects.get(1);
System.out.println("AFTER User address: " + afterUserAddress);
Output:
BEFORE User: User{email=norman#localhost, name=Norman, age=26, isDeveloper=true}
BEFORE User address: UserAddress{country=Germany, city=Magdeburg, street=Main Street, houseNumber=42A}
JSON: {"email":"norman#localhost","name":"Norman","age":26,"isDeveloper":true,"country":"Germany","city":"Magdeburg","street":"Main Street","houseNumber":"42A"}
AFTER User: User{email=norman#localhost, name=Norman, age=26, isDeveloper=true}
AFTER User address: UserAddress{country=Germany, city=Magdeburg, street=Main Street, houseNumber=42A}
As you can see, you don't need to create extra DTO classes to cover all the cases, but this also requires a little more memory usage due to the use of trees here.
I find a solution with use Gson tools (class UserAddressAdapter extends TypeAdapter<UserAddress>).
public class User {
...
// see the first ligne of UserAddressAdapter#write
// city => (out.value(value.getCity());)
#SerializedName("city")
#JsonAdapter(UserAddressAdapter.class)
private final UserAddress userAddress;
...
}
public class UserAddressAdapter extends TypeAdapter<UserAddress> {
#Override
public void write(JsonWriter out, UserAddress value) throws IOException {
out.value(value.getCity());
out.name("country");
out.value(value.getCountry());
out.name("houseNumber");
out.value(value.getHouseNumber());
out.name("street");
out.value(value.getStreet());
}
#Override
public UserAddress read(JsonReader in) throws IOException {
final int city = in.nextInt();
UserAddress[] scopes = UserAddress.values();
for (UserAddress scope : scopes) {
if (scope.getCity() == city) {
return scope;
}
}
return null;
}
}
and caller is:
new Gson().toJson(new User("...", ...))
How to genearate "_id" : "01A63D2B-1724-456E-B2C0-3B3729951654" instead of "_id" : ObjectId("570602c46399e320c3022c6b")
My Student.class
#Entity("student")
public class Student {
#Id
private String Id;
private long studentId;
private String studentName;
private String qualification;
public Student(){
}
public Student(long studentId, String studentName, String qualification) {
this.studentId = studentId;
this.studentName = studentName;
this.qualification = qualification;
}
public long getStudentId() {
return studentId;
}
public void setStudentId(long studentId) {
this.studentId = studentId;
}
public String getStudentName() {
return studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
public String getQualification() {
return qualification;
}
public void setQualification(String qualification) {
this.qualification = qualification;
}
}
Function to add JSON Data to MOngoDB:
public void importFromJsonToMongoDB(File file) throws FileNotFoundException{
try{
String strJson = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
JSONArray jsonArr = new JSONArray(strJson);
for (int i = 0; i < jsonArr.length(); i++)
{
JSONObject jsonObj = jsonArr.getJSONObject(i);
String str = jsonObj.toString();
ObjectMapper mapper = new ObjectMapper();
Student std = mapper.readValue(str, Student.class);
sr.save(std);
}
}catch (Exception e) {
e.printStackTrace();
System.out.println("Error While parsing data");
}
* How to Auto Generate id? rather than MongoDb generating it.
I think you need to add "_id" field while inserting the document in MongoDB. since you are not specifying any "_id" field it will automatically be generated by MongoDB. You can also use getNextSequence() method of mongodb to generate the id according to your preference.
Note: StudentID and _id are two different entities in the same document.
I hope these link will be useful for you:
https://docs.mongodb.org/manual/tutorial/create-an-auto-incrementing-field/
Replace the existing NO-arg Constructor with following one in
Student.class
public Student(){
super();
id = UUID.randomUUID().toString();
}
This will generate random id instead of MongoDB ObjectId