I'm using JacksonAnnotation along with Spring Framework to parse a JSON that I get from a web service for my app.
I have the same data structure coming from two distinct methods but there is a field in one of them that comes capitalized. I don't want to create two data structures just because of that.
Is there any way that I make JsonGetter case insensitive or at least make it accept two version of a string?
Currently I have to use this for method A
#JsonGetter("CEP")
public String getCEP() {
return this.cep;
}
and this for method B
#JsonGetter("Cep")
public String getCEP() {
return this.cep;
}
Thanks
You can create new setter method for each possibility of property name:
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonProgram {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.readValue("{\"Cep\":\"value\"}", Entity.class));
System.out.println(mapper.readValue("{\"CEP\":\"value\"}", Entity.class));
}
}
class Entity {
private String cep;
public String getCep() {
return cep;
}
#JsonSetter("Cep")
public void setCep(String cep) {
this.cep = cep;
}
#JsonSetter("CEP")
public void setCepCapitalized(String cep) {
this.cep = cep;
}
#Override
public String toString() {
return "Entity [cep=" + cep + "]";
}
}
Related
public static class One {
#Override
public String interact(String... values) {
String actualTextOne = "test";
return actualTextOne;
}
}
public static class Two {
#Override
public String interact(String... values) {
String actualTextTwo = "test";
/* Here I need to compare actualTextOne and actualTextTwo, but the problem is that I can't find solluction how to use actualTextOne in Two class*/
return actualTextTwo;
}
}
You cannot do that.
Please check variable scope in java.
https://www.codecademy.com/articles/variable-scope-in-java
A possible solution here is to call the method interact from the class One. Something like this
public static class Two {
#Override
public String interact(String... values) {
String actualTextTwo = "test";
One one = new One();
String actualTextOne = one.interact(values);
// compare values here
return actualTextTwo;
}
}
Why in your classes functions have parameters if you dont use it?
You can mark your class with static only if he is nested, else you need do like this:
class Two {
static public String interact(String... values) {
String actualTextTwo = "test";
return actualTextTwo;
}
}
String textOne = One.interact("");
String textTwo = Two.interact("");
System.out.println(textOne==textTwo);
I am creating a small utility on JAVA flink API to learn the functionalities. I am trying to read csv file and just print it and I have developed a POJO class for the structure of the data. When I executed the code, I dont see the right values.(Integers values are replaced with zeros and null values for String. How do I map the datatype for the attributes
My Main Class:
package org.karthick.flinkLab;
import org.apache.flink.api.java.DataSet;
import org.apache.flink.api.java.ExecutionEnvironment;
import javax.xml.crypto.Data;
public class CSVFileRead {
public static void main(String[] args) throws Exception {
System.out.println("--CSV File Reader using Flink's Data Set API--");
ExecutionEnvironment execEnv = ExecutionEnvironment.getExecutionEnvironment();
DataSet<DataModel> csvInput = execEnv.readCsvFile("C:\\Flink\\Data\\IndividualDetails.csv")
.pojoType(DataModel.class);
csvInput.print();
}
}
My Pojo class (DataModel.class)
package org.karthick.flinkLab;
import org.apache.flink.api.java.tuple.Tuple;
import org.apache.flink.api.java.tuple.Tuple12;
import java.io.Serializable;
import java.util.Date;
public class DataModel<T extends Tuple>
extends Tuple12<Integer,String,Date,Integer,String,String,String,String,String,String,Date,String>
implements Serializable
{
public Integer id;
public String government_id;
public Date diagnosed_date;
public Integer age;
public String detected_city;
public String detected_district;
public String detected_state;
public String nationality;
public String current_status;
public Date status_change_date;
public String notes;
public DataModel() {};
public String getNotes() {
return notes;
}
public Date getStatus_change_date() {
return status_change_date;
}
public String getCurrent_status() {
return current_status;
}
public String getNationality() {
return nationality;
}
public String getDetected_state() {
return detected_state;
}
public String getDetected_district() {
return detected_district;
}
public String getDetected_city() {
return detected_city;
}
public String gender ;
public Date getDiagnosed_date() {
return diagnosed_date;
}
public String getGender() {
return gender;
}
public Integer getAge() {
return age;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getGovernment_id() {
return government_id;
}
public void setGovernment_id(String government_id) {
this.government_id = government_id;
}
}
When I executed the main method, I dont see the proper values. Sample result
(0,,Tue May 19 16:50:38 IST 2020,0,,,,,,,Tue May 19 16:50:38 IST 2020,)
where as I expect something like
(2777,AP,Tue May 19 16:50:38 IST 2020,0,A,B,C,D,E,F,Tue May 19 16:50:38 IST 2020,G)
What could be missing here?
You are missing the column mapping from CSV to POJO. Adding the mapping will work. The mapping of the column names must follow the following two rules:
The column names should be exactly the same names as in POJO.
The order of the columns in the mapping should be exactly the same as in the CSV file.
You can define the mapping as follows:
DataSet<DataModel> csvInput = execEnv.readCsvFile("C:\\Flink\\Data\\IndividualDetails.csv")
.pojoType(DataModel.class, "id", "age",.........);
It should have thrown error but it hasn't. It could be a bug
I have some validations in my "command", parameter of the controller that are executed within the set of each attribute, the problem is that the attributes not informed, jackson does not invoke the set method to do the validation. Is it possible to force Jackson to invoke the Set method even when the attribute is missing?
For exemple Payload without agency field:
{
"bank": "237",
"account": "20772-1",
"taxId": "36456155800",
"paidAmount": 30.00
}
My Controller:
public Return confirmTransfer(#RequestBody RechargeTransferConfirmationCommand command) {
System.out.println(command);
}
Class Java:
public class RechargeTransferConfirmationCommand {
public static final String ERR_INVALID_AGENCY = "Agency number can not be null.";
private String bank;
private String account;
private String agency;
private String taxId;
public RechargeTransferConfirmationCommand(BigDecimal paidAmount, String bank, String account,
String agency, String taxId) {
setPaidAmount(paidAmount);
setBank(bank);
setAccount(account);
setAgency(agency);
setTaxId(taxId);
}
public void setRechargeId(RechargeId rechargeId) {
assertArgumentNotNull(rechargeId, Recharge.ERR_RECHARGE_ID_INVALID);
this.rechargeId = rechargeId;
}
private void setPaidAmount(BigDecimal paidAmount) {
if (paidAmount == null || paidAmount.compareTo(BigDecimal.ZERO) < 0)
throw new IllegalArgumentException(Recharge.ERR_INVALID_AMOUNT);
this.paidAmount = paidAmount;
}
private void setBank(String bank) {
assertArgumentNotEmpty(bank, TransferInformation.ERR_INVALID_BANK_NUMBER);
this.bank = bank;
}
private void setAccount(String account) {
assertArgumentNotEmpty(account, TransferInformation.ERR_INVALID_ACCOUNT);
this.account = account;
}
private void setAgency(String agency) {
assertArgumentNotEmpty(agency, ERR_INVALID_AGENCY);
this.agency = agency;
}
private void setTaxId(String taxId) {
assertArgumentNotEmpty(taxId, ERR_INVALID_TAX_ID);
this.taxId = taxId;
}
}
In this case, for each field the set method is invoked to do the validation, except the agency field that was not informed in the payload, it should soon throw the exception contained in the method assertArgumentNotEmpty.
yes jackson will not invoke the setter methods of fields that are not passed in payload, if you want to validate missing fields you need custom Deserializer
class RechargeTransferConfirmationCommandDeserializer extends JsonDeserializer<RechargeTransferConfirmationCommand> {
#Override
public RechargeTransferConfirmationCommand deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
RechargeTransferConfirmationCommand responseModel = jp.readValueAs(RechargeTransferConfirmationCommand.class);
RechargeTransferConfirmationCommand finalModel = new RechargeTransferConfirmationCommand();
finalModel.set agency(responseModel. agency == null || age.trim().isEmpty() ? "agency" : responseModel.agency);
return finalModel;
}
}
And you model should be
#JsonDeserialize(using = DefaultModelDeserializer.class)
public class DefaultModel {
...
}
use #JsonSetter in method && declare no args constructor also:
public RechargeTransferConfirmationCommand(){
}
#JsonSetter
public void setRechargeId(RechargeId rechargeId) {
assertArgumentNotNull(rechargeId, Recharge.ERR_RECHARGE_ID_INVALID);
this.rechargeId = rechargeId;
}
But better you use javax validation. Look at this to get details.
Another way:
You can write all validtion in one method and use #AssertTrue:
#AssertTrue
public boolean isValid(){
//if all field is valid then return true;
return false;
}
problem solved using #JsonCreator, thank you all for your help
#JsonCreator
public RechargeTransferConfirmationCommand(#JsonProperty("paidAmount") BigDecimal paidAmount,
#JsonProperty("bank") String bank, #JsonProperty("account") String account,
#JsonProperty("agency") String agency, #JsonProperty("taxId") String taxId) {
setPaidAmount(paidAmount);
setBank(bank);
setAccount(account);
setAgency(agency);
setTaxId(taxId);
}
I have used One-to-Many Mapping in my project. I have stored a list of clicks for every user.
But when I retrieve the list by calling getClicks() methodm Hibernate returns list in different format.
Something like this.
"[com.zednx.tech.persistence.Click#29df9a77]"
So I tried Reading Every value from the list and assign to a new List.
List<Click> clicks=new ArrayList<Click>();
for(Click c: e.getClicks()){
Click temp = new Click();
temp.setAff_source(c.getAff_source());
temp.setCb_to_award(c.getCb_to_award());
temp.setCb_type(c.getCb_type());
clicks.add(temp);
}
But when i print the items of new List it stills prints the same way.
I need to build a JSON from the resulting String of this list.
So if the list is returned in format, it wont help me.
I couldn't find anything regarding this except How to pretty print Hibernate query results?
I tried Arrays.ToString(Object o). But it doesn't work.
GSON builder part-
Gson gson = new GsonBuilder()
.registerTypeAdapter(Click.class, new MyTypeAdapter<Click>())
.create();
List<Click> clicks=new ArrayList<Click>();
for(Click c: e.getClicks()){
Click temp = new Click();
temp.setAff_source(c.getAff_source());
temp.setCb_to_award(c.getCb_to_award());
temp.setCb_type(c.getCb_type());
temp.setCom_to_recieve(c.getCom_to_recieve());
temp.setStore_name(c.getStore_name());
temp.setT_date(c.getT_date());
temp.setT_status(c.getT_status());
temp.setT_ticket(c.getT_ticket());
temp.setUid(c.getUid());
System.out.println(c.toString());
clicks.add(temp);
}
String json = gson.toJson(clicks, Click.class);
Click.java
#Entity
#Table(name="click")
public class Click {
#Id
#Column(name="t_ticket")
private String t_ticket;
#Column(name="uid",nullable=false)
private long uid;
public long getUid() {
return uid;
}
public void setUid(long uid) {
this.uid = uid;
}
#ManyToOne
#JoinColumn(name="uid",
insertable=false, updatable=false,
nullable=false)
private Earning earning;
#Column(name="store_name")
private String store_name;
#Column(name="t_status")
private String t_status;
#Column(name="aff_source")
private String aff_source;
#Column(name="com_to_recieve")
private float com_to_recieve;
#Column(name="t_date")
private Date t_date;
#Column(name="cb_to_award")
private float cb_to_award;
#Column(name="cb_type")
private String cb_type;
public String getT_ticket() {
return t_ticket;
}
public void setT_ticket(String t_ticket) {
this.t_ticket = t_ticket;
}
public Earning getEarning() {
return earning;
}
public void setEarning(Earning earning) {
this.earning = earning;
}
public String getStore_name() {
return store_name;
}
public void setStore_name(String store_name) {
this.store_name = store_name;
}
public String getT_status() {
return t_status;
}
public void setT_status(String t_status) {
this.t_status = t_status;
}
public String getAff_source() {
return aff_source;
}
public void setAff_source(String aff_source) {
this.aff_source = aff_source;
}
public float getCom_to_recieve() {
return com_to_recieve;
}
public void setCom_to_recieve(float com_to_recieve) {
this.com_to_recieve = com_to_recieve;
}
public Date getT_date() {
return t_date;
}
public void setT_date(Date t_date) {
this.t_date = t_date;
}
public float getCb_to_award() {
return cb_to_award;
}
public void setCb_to_award(float cb_to_award) {
this.cb_to_award = cb_to_award;
}
public String getCb_type() {
return cb_type;
}
public void setCb_type(String cb_type) {
this.cb_type = cb_type;
}
Any Help is appreciated.
You need to implement a toString method, as your current Click class likely doesn't have one, so it just prints as the name of the class and instance identifier.
Okay, I could solve my problem finally.
I made another POJO without any annotations and Mapped the List items to that POJO class.
I think the problem was with Annotation of mapping on another class which I had in original POJO.
Also getString() method only helps in changing format of identifier. So basically it has nothing to do with JSON building unless you format getString() in form of JSON.
Hope it helps. If anyone wants new temp POJO I made I can post it if requested.
Thanks.
I have a couple of objects from which selected members should be combined to create an output object. All these are POJOs. I am seeing that all object mappers work on a single POJO to another POJO level. Is there any mapper that supports what I am looking for? Of course, I understand that there is some mapping stuff that I need to specify.
Edit:
I know how to get this done by writings own Java class. I am just looking for a way to do it with one of the mapping libraries.
You aren't limited in what you require to be passed to your mapper. You can define it to accept several items and build the object based on the multiple inputs. Here is an example:
public class ClassOne {
private final String someProperty;
public ClassOne(String someProperty) {
this.someProperty = someProperty;
}
public String getSomeProperty() {
return someProperty;
}
}
public class ClassTwo {
private final String someOtherProperty;
public ClassTwo(String someOtherProperty) {
this.someOtherProperty = someOtherProperty;
}
public String getSomeOtherProperty() {
return someOtherProperty;
}
}
public class CombinedClass {
public static CombinedClass mapper(ClassOne one, ClassTwo two){
return new CombinedClass(one.getSomeProperty(), two.getSomeOtherProperty());
}
private final String someProperty;
private final String someOtherProperty;
private CombinedClass(String someProperty, String someOtherProperty) {
this.someProperty = someProperty;
this.someOtherProperty = someOtherProperty;
}
public String getSomeProperty() {
return someProperty;
}
public String getSomeOtherProperty() {
return someOtherProperty;
}
}