Creating a string list from RestTemplate - java

I am using restTemplate to retrieve data from a url, and I get it as a List of Objects but I need a List of Strings to be able to filter it (I want to remove duplicates and change some attribute names).
This is my Template:
public static Provinces restTemplateProvince(RestTemplate restTemplate) {
String ProvinceCommunityURL = "https://www.el-tiempo.net/api/json/v2/provincias";
Provinces province = restTemplate.getForObject(ProvinceCommunityURL, Provinces.class);
return province;
}
Now I want to filter this data and show it in my own API. I'm able to show it with the following:
RestController
public class ShowcaseController {
#Autowired
ProvinceService provinceService;
#GetMapping("/provinces")
public Provinces getAllProvinces(){
return provinceService.getAllProvinces();
}
}
#Service
public class ProvinceService {
#Autowired
RestTemplate restTemplate;
public Provinces getAllProvinces(){
Provinces listOfProvinces = Templates.restTemplateProvince(searchList);
return listOfProvinces;
}
}
But I can't filter it in this list type.
How could I do it?
My Province class:
#JsonIgnoreProperties(ignoreUnknown = true)
public class Provinces {
#JsonProperty("provincial")
private List<ProvincesData> provinces;
public Provinces(){}
public Provinces(List<ProvincesData> provinces) {
this.provinces = provinces;
}
#JsonProperty("provincial")
public List<ProvincesData> getprovinces() {
return provinces;
}
#JsonProperty("Test")
public void setprovinces(List<ProvincesData> provinces) {
this.provinces = provinces;
}
}
And ProvinceData class:
#JsonIgnoreProperties(ignoreUnknown = true)
public class ProvincesData {
#JsonProperty("CODPROV")
private String codProv;
#JsonProperty("NOMBRE_PROVINCIA")
private String nomeProvincia;
#JsonProperty("CODAUTON")
private String codAuton;
#JsonProperty("COMUNIDAD_CIUDAD_AUTONOMA")
private String comunidadeCidadeAutonoma;
public ProvincesData(){
}
public ProvincesData(String codProv, String nomeProvincia, String codAuton, String comunidadeCidadeAutonoma){
this.codProv = codProv;
this.nomeProvincia = nomeProvincia;
this.codAuton = codAuton;
this.comunidadeCidadeAutonoma = comunidadeCidadeAutonoma;
}
#JsonProperty("CODPROV")
public String getCodProv() {
return codProv;
}
#JsonProperty("Test")
public void setCodProv(String codProv) {
this.codProv = codProv;
}
public String getNomeProvincia() {
return nomeProvincia;
}
public void setNomeProvincia(String nomeProvincia) {
this.nomeProvincia = nomeProvincia;
}
public String getCodAuton() {
return codAuton;
}
public void setCodAuton(String codAuton) {
this.codAuton = codAuton;
}
public String getComunidadeCidadeAutonoma() {
return comunidadeCidadeAutonoma;
}
public void setComunidadeCidadeAutonoma(String comunidadeCidadeAutonoma) {
this.comunidadeCidadeAutonoma = comunidadeCidadeAutonoma;
}
}
The filter to isolate the codAuton and comunidadeCidadeAutonoma columns without repeating. If possible, build a new list with only the data I want and change de variable name so that I can then show them in my API with different titles and such.
Regards.

Update your service to something like:
public static Provinces restTemplateProvince(RestTemplate restTemplate) {
String ProvinceCommunityURL = "https://www.el-tiempo.net/api/json/v2/provincias";
Provinces province = restTemplate.getForObject(ProvinceCommunityURL, Provinces.class);
List<String> included = new ArrayList<>();
List<ProvincesData> filtered = province.getprovinces()
.stream().filter(p -> {
if (included.contains(p.getCodAuton())) {
return false;
} else {
included.add(p.getCodAuton());
return true;
}
})
.collect(Collectors.toList());
province.setprovinces(filtered);
return province;
}
Could be done more efficiently but it is probably more readable like this.

Related

is it possible to convert statement result to List<Object> in java

I want to convert the below statement result to list of my object.
import com.amazonaws.services.dynamodbv2.model.ExecuteStatementResult;
ExecuteStatementResult executeStatementResult = dynamoDB.executeStatement(executeStatementRequest);
System.out.println( executeStatementResult.getItems() );
Output:
[{bookingClasses={S: A,B,C,}, suppliers={S: BA,1A,TF,}, adjustmentType={S: PERCENTAGE,}, departureStartDate={S: 2022-11-17,}}]
Please note .getItems() method is like below:
public java.util.List<java.util.Map<String, AttributeValue>> getItems() {
return items;
}
I want something like this to work for me:
List<java.util.Map<String, AttributeValue>> items = executeStatementResult.getItems();
List<PricingRule> pricingRules = ( List<PricingRule> ) items;
Any help suggestion or workaround appreciated.
Thank you
You can't cast directly so you will need to implement something like PricingRule::fromMap and do something like
class PricingRule {
// everything you already have
public static PricingRule fromMap(Map<String, AttributeValue> items) {
// create PricingRule
}
}
Then when you need your list you can use something like
List<java.util.Map<String, AttributeValue>> items = executeStatementResult.getItems();
// assumes java 17+, alternatively use .collect(Collectors.toList())
List<PricingRule> pricingRules = items.stream().map(PricingRule::fromMap).toList();
Glad you managed to solve your problem, but have you considered using the table resource?
var table = dynamoDbEnhancedClient.table("TableName", TableSchema.fromClass(PricingRule.class));
List<PricingRule> items = table.query(<condition>).items().stream().toList();
This code requires that PricingRule is defined as a dynamo bean, for example
#DynamoDbBean
public class PricingRule {
private String pk;
private String sk;
private String field1;
private String field2;
public PricingRule() {
}
#DynamoDbPartitionKey
public String getPk() {
return pk;
}
public void setPk(String pk) {
this.pk = pk;
}
#DynamoDbSortKey
public String getSk() {
return sk;
}
public void setSk(String sk) {
this.sk = sk;
}
public String getField1() {
return field1;
}
public void setField1(String field1) {
this.field1 = field1;
}
public String getField2() {
return field2;
}
public void setField2(String field2) {
this.field2 = field2;
}
}
I got solution and posting if someone may come up with this problem in future.
public List<PricingRule> statementToList() {
List<PricingRule> pricingRules = new ArrayList<>();
try {
// Create ExecuteStatementRequest
ExecuteStatementRequest executeStatementRequest = createExecuteStatementRequest();
ExecuteStatementResult executeStatementResult = dynamoDB.executeStatement(executeStatementRequest);
final ObjectMapper mapper = new ObjectMapper();
executeStatementResult.getItems().forEach(item -> pricingRules.add(mapper.convertValue(ItemUtils.toSimpleMapValue(item), PricingRule.class)));
} catch (Exception e) {
handleExecuteStatementErrors(e);
}
return pricingRules;
}

#RestController autoserialize POJO's

I have a Spring mvc application, with a #RestController like such:
#RestController
#RequestMapping("levels")
public class LevelController {
private final GetLevelOneCount getLevelOneCount;
private final GetLevelTwoCount getLevelTwoCount;
private final GetLevelThreeCount getLevelThreeCount;
#Inject
public LevelController(GetLevelOneCount getLevelOneCount,
GetLevelTwoCount getLevelTwoCount,
GetLevelThreeCount getLevelThreeCount) {
this.getLevelOneCount = getLevelOneCount;
this.getLevelTwoCount = getLevelTwoCount;
this.getLevelThreeCount = getLevelThreeCount;
}
#GetMapping("/level1/{id}")
public LevelModel levelOne(#PathVariable String id) throws SQLException {
LevelModel levelOneModel = new LevelModel();
levelOneModel.setLevelQuery(getLevelOneCount.execute(id));
levelOneModel.setLevelDirQuery(getLevelOneCount.executeDir(id));
levelOneModel.setLevelDateQuery(getLevelOneCount.executeDate(id));
return levelOneModel;
}
my LevelModel is a POJO with private variables, now i wonder, if this can get serialized to propper JSON with private variables?
package com.pwc.tag.service.levels;
public class LevelModel {
private Long LevelQuery;
private Long LevelDirQuery;
private Long LevelDateQuery;
public Long getLevelQuery() {
return LevelQuery;
}
public void setLevelQuery(Long levelQuery) {
LevelQuery = levelQuery;
}
public Long getLevelDirQuery() {
return LevelDirQuery;
}
public void setLevelDirQuery(Long levelDirQuery) {
LevelDirQuery = levelDirQuery;
}
public Long getLevelDateQuery() {
return LevelDateQuery;
}
public void setLevelDateQuery(Long levelDateQuery) {
LevelDateQuery = levelDateQuery;
}
}
Yes, your object will be serialized to a proper JSON structure including the private field, because of the getters and setters.
If these fields should not be present in the output object, you can add the #JsonIgnore annotation to exclude them from the JSON structure.
P.S. the common approach is to start names of java properties with a lower case letter.

Dynamic Request body REST API Method using swagger

I have use case were I need to get requestBody based on selection of field.below is same code which I was able get the dynamic responseBody Based on selection ProtocolType.Is there is any way that swagger can read the RequestBody Dynamically.
Controller.Java
#ApiOperation(value = "Protocol Account", tags = {"ProtocolAccount"})
#RequestMapping(value = "/protocolAccount/{protocolName}",
method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody public ProtocolAccount getProtocol(#PathVariable String protocolName)
{
return service.getProtocol(protocolName);
}
Service.Java
public ProtocolAccount getProtocol(String protocolName){
ProtocolAccount protocolAccount=new ProtocolAccount();
Object object=ProtocolType.fromMap(protocolName);
protocolAccount.setProtocol(object);
return protocolAccount;
}
POJOs
public class ProtocolAccount
{
String Id;
private Object protocolType
}
public class Protocol{
private String port;
}
public class FTPProtocol extends Protocol{
/*Some Fields*/
}
public class SFTPProtocol extends Protocol{
/*Some Fields*/
}
Enumeration
public enum ProtocolType
{
SFTP("SFTP"), FTPS("FTPS"), AS2("AS2"), FTP("FTP");
private final String value;
private static final EnumMap<ProtocolType,
Object>map = new EnumMap<ProtocolType, Object>(ProtocolType.class);
static{
map.put(ProtocolType.SFTP, new SFTPProtocol());
map.put(ProtocolType.FTP, new FTPProtocol());
map.put(ProtocolType.FTPS,new FTPSProtocol());
}
ProtocolType(String v){
value=v;
}
public static ProtocolType fromValue(String val){
return EnumSet.allOf(ProtocolType.class)
.stream().filter(e->e.value.equals(val))
.findFirst().orElseThrow(()->new IllegalArgumentException(val));
}
public String value(){
return value;
}
public static Object fromMap(String value)
{
return map.get(ProtocolType.fromValue(value));
}
}

Mapping JSON into POJO using Gson

I have the following JSON to represent the server response for a salt request:
{
"USER":
{
"E_MAIL":"email",
"SALT":"salt"
},
"CODE":"010"
}
And i tried to map it with the following POJO:
public class SaltPOJO {
private String code = null;
private User user = null;
#Override
public String toString() {
return this.user.toString();
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public class User {
private String e_mail = null;
private String salt = null;
#Override
public String toString() {
return this.e_mail + ": " + this.salt;
}
public String getE_mail() {
return e_mail;
}
public void setE_mail(String e_mail) {
this.e_mail = e_mail;
}
public String getSalt() {
return salt;
}
public void setSalt(String salt) {
this.salt = salt;
}
}
}
Now everytime i do this:
Gson gson = new Gson();
SaltPOJO saltPojo = gson.fromJson(json.toString(), SaltPOJO.class);
Log.v("Bla", saltPojo.toString());
The saltPojo.toString() is null. How can i map my JSON into POJO using Gson?
Is the order of my variables important for the Gson mapping?
Is the order of my variables important for the Gson mapping?
No, that's not the case.
How can i map my JSON into POJO using Gson?
It's Case Sensitive and the keys in JSON string should be same as variable names used in POJO class.
You can use #SerializedName annotation to use any variable name as your like.
Sample code:
class SaltPOJO {
#SerializedName("CODE")
private String code = null;
#SerializedName("USER")
private User user = null;
...
class User {
#SerializedName("E_MAIL")
private String e_mail = null;
#SerializedName("SALT")
private String salt = null;
You don't have proper mapping between your getter and setter. If you change your json to something like below, it would work:
{
"user":
{
"email":"email",
"salt":"salt"
},
"code":"010"
}
If you are getting json form third party then unfortunately, you would have to change your pojo or you could use adapter.

Json API Parsing troubles with Java

I'm running into a few issues similar to what others have had in the past with Json parsing in Java. This is the first time I try something like this so any help/tips is extremely useful.
I'm trying to parse in data from this site: https://api.bitcoinaverage.com/exchanges/USD
I have tried numerous ways with both Json and Gson. And have tried looking for help here but to no avail.
Here are the classes that are set up (these were auto generated):
Info.java:
public class Info{
private String display_URL;
private String display_name;
private Rates[] rates;
private String source;
private Number volume_btc;
private Number volume_percent;
public String getDisplay_URL(){
return this.display_URL;
}
public void setDisplay_URL(String display_URL){
this.display_URL = display_URL;
}
public String getDisplay_name(){
return this.display_name;
}
public void setDisplay_name(String display_name){
this.display_name = display_name;
}
public Rates[] getRates(){
return this.rates;
}
public void setRates(Rates[] rates){
this.rates = rates;
}
public String getSource(){
return this.source;
}
public void setSource(String source){
this.source = source;
}
public Number getVolume_btc(){
return this.volume_btc;
}
public void setVolume_btc(Number volume_btc){
this.volume_btc = volume_btc;
}
public Number getVolume_percent(){
return this.volume_percent;
}
public void setVolume_percent(Number volume_percent){
this.volume_percent = volume_percent;
}
}
Rates.java:
public class Rates {
private Number ask;
private Number bid;
private Number last;
public Number getAsk(){
return this.ask;
}
public void setAsk(Number ask){
this.ask = ask;
}
public Number getBid(){
return this.bid;
}
public void setBid(Number bid){
this.bid = bid;
}
public Number getLast(){
return this.last;
}
public void setLast(Number last){
this.last = last;
}
}
MainClass.java:
public class MainClass {
public static void main(String[] args) throws Exception {
Gson gson = new Gson();
String json = readUrl("https://api.bitcoinaverage.com/exchanges/USD");
Info page = gson.fromJson(json, Info.class);
System.out.println(page.getDisplay_name());
}
private static String readUrl(String urlString) throws Exception {
BufferedReader reader = null;
try {
URL url = new URL(urlString);
reader = new BufferedReader(new InputStreamReader(url.openStream()));
StringBuffer buffer = new StringBuffer();
int read;
char[] chars = new char[1024];
while ((read = reader.read(chars)) != -1)
buffer.append(chars, 0, read);
return buffer.toString();
} finally {
if (reader != null)
reader.close();
}
}
}
When I try to call a getter, a null is returned.
How do I go about parsing the data properly, and then being able to call an attribute from which ever object I want? For example, if I want an attribute from "anx_hk" or "bitfinex".
This is the first time me posting something here so I hope I'm following the proper guidelines.
I also plan on passing this over to Android once I get the fell for parsing Json better. Thanks for the help! It'll greatly be appreciated.
I'll be honest with you, that's a pretty lame API response. Here it is
{
"anx_hk": {
"display_URL": "https://anxbtc.com/",
"display_name": "ANXBTC",
"rates": {
"ask": 454.26,
"bid": 444.46,
"last": 443.78
},
"source": "bitcoincharts",
"volume_btc": 11.73,
"volume_percent": 0.02
},
...,
"timestamp": "Fri, 04 Apr 2014 04:30:26 -0000",
...
}
There's no JSON array here, so you can get rid of all your array types. This response is a JSON object, which contains a bunch of JSON objects (which share a format) and a JSON name value pair where the name is timestamp.
The common JSON objects have two fields of type double (that's what type your field should be, not Number)
"volume_btc": 11.73,
"volume_percent": 0.02
, three fields of type String
"display_URL": "https://anxbtc.com/",
"display_name": "ANXBTC",
"source": "bitcoincharts",
and one that is a JSON object that contains three more doubles
"rates": {
"ask": 454.26,
"bid": 444.46,
"last": 443.78
}
The actual issue here is that, I'm assuming, the JSON objects in the root JSON object have names that may change or new ones may be added. This is not a good fit for a POJO. Instead you'd want to use a Map<String, Info>, but Gson can't map to that by default. It is not well suited for such deserialization. You'd have to provide your own TypeAdapter.
Instead, I'm going to suggest you use Jackson.
If we put that all together, we get something like
class ApiResponse {
private Map<String, Info> page = new HashMap<>();
private Date timestamp;
public Map<String, Info> getPage() {
return page;
}
#JsonAnySetter
public void setPage(String name, Info value) {
page.put(name, value);
}
public Date getTimestamp() {
return timestamp;
}
public void setTimestamp(Date timestamp) {
this.timestamp = timestamp;
}
}
class Info {
private String display_URL;
private String display_name;
private Rates rates;
private String source;
private Double volume_btc;
private Double volume_percent;
public String getDisplay_URL() {
return this.display_URL;
}
public void setDisplay_URL(String display_URL) {
this.display_URL = display_URL;
}
public String getDisplay_name() {
return this.display_name;
}
public void setDisplay_name(String display_name) {
this.display_name = display_name;
}
public Rates getRates() {
return this.rates;
}
public void setRates(Rates rates) {
this.rates = rates;
}
public String getSource() {
return this.source;
}
public void setSource(String source) {
this.source = source;
}
public Double getVolume_btc() {
return this.volume_btc;
}
public void setVolume_btc(Double volume_btc) {
this.volume_btc = volume_btc;
}
public Double getVolume_percent() {
return this.volume_percent;
}
public void setVolume_percent(Double volume_percent) {
this.volume_percent = volume_percent;
}
}
class Rates {
private Double ask;
private Double bid;
private Double last;
public Number getAsk() {
return this.ask;
}
public void setAsk(Double ask) {
this.ask = ask;
}
public Double getBid() {
return this.bid;
}
public void setBid(Double bid) {
this.bid = bid;
}
public Double getLast() {
return this.last;
}
public void setLast(Double last) {
this.last = last;
}
}
With deserialization code such as
String json = readUrl("https://api.bitcoinaverage.com/exchanges/USD");
ObjectMapper mapper = new ObjectMapper();
ApiResponse response = mapper.readValue(json, ApiResponse.class);
System.out.println(response);
With appropriate toString() methods (mine were auto-generated with Eclipse), you would get something like
ApiResponse [pages={bitkonan=Info [display_URL=https://bitkonan.com/, display_name=BitKonan, rates=Rates [ask=475.0, bid=438.01, last=437.0], source=api, volume_btc=7.24, volume_percent=0.01], vaultofsatoshi=Info [display_URL=https://vaultofsatoshi.com, display_name=Vault of Satoshi, rates=Rates [ask=460.0, bid=460.0, last=460.0], source=api, volume_btc=11.46, volume_percent=0.02], bitstamp=Info [display_URL=https://bitstamp.net/, display_name=Bitstamp, rates=Rates [ask=439.16, bid=436.34, last=436.34], source=api, volume_btc=22186.29, volume_percent=35.19], ...}, timestamp=Fri Apr 04 01:02:43 EDT 2014]
as output.
The api response contains many objects, but seems that you are trying to read them as a single Info object.
You may try to read the response as a Map<String, Info>, and iterate the entries.
Map<String, Info> hashMap = gson.fromJson(body, HashMap.class);
for (Map.Entry entry : hashMap.entrySet()) {
// your code
}

Categories