I have some problem where I am getting my data from my API call when I print in the console. I am getting {id: 0000, label: TEST} as my results. What I need to do is populate the label to show in my dropdown as a value where the user can select from. Is there a way with my code below? thanks for the help.
Here is my code:
Using Jersey Library:
public List<JobSearchItem> getjobSearchList() {
Client restClient = ClientBuilder.newClient();
Response response = restClient.target("https://api.myjson.com/bins/7xq2x").request(MediaType.APPLICATION_JSON).get();
return response.readEntity(new GenericType<List<JobSearchItem>>() {});
}
#Override
public String toString() {
return new StringBuilder().append("[value=").append(value).append(", label=").append(label).append("]")
.toString();
}
As I mentioned in the comment, it is very easy if you use a library or framework that does the heavy lifting for you. Here's a very simple example of retrieving the list using Jersey.
import java.util.List;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
public class ListExtractor {
public static void main(String[] args) {
Client restClient = ClientBuilder.newClient();
Response response = restClient.target("https://api.myjson.com/bins/7xq2x").request(MediaType.APPLICATION_JSON).get();
List<Item> items = response.readEntity(new GenericType<List<Item>>() {});
items.forEach(System.out::println);
}
static class Item {
private String name;
private String abbreviation;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAbbreviation() {
return abbreviation;
}
public void setAbbreviation(String abbreviation) {
this.abbreviation = abbreviation;
}
#Override
public String toString() {
return new StringBuilder().append("[name=").append(name).append(", abbreviation=").append(abbreviation).append("]")
.toString();
}
}
}
UPDATE
I just modified the code a bit, so that it returns a list of items.
Warning: this is not production ready code. I haven't added any exception handling or logging, so that it remains short and conveys its purpose in a clear way.
You need to familiarise yourself with JSON serialisers/deserialisers, in order to understand what's going in the above example.
Explanation
If you look at the response from the link (https://api.myjson.com/bins/7xq2x), you see that it returns a JSON array, where each element of the array is:
{"name":"Alberta","abbreviation":"AB"}. The JSON deserialiser provided by Jersey can convert (deserialise) this JSON object into a Java object if you have a class that has two fields named name and abbreviation (and their corresponding getters and setters).
This line of code
response.readEntity(new GenericType<List<Item>>() {});
will work out of the box because we have provided the Item class with fields named just like the keys in the JSON object above:
class Item {
private String name;
private String abbreviation;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAbbreviation() {
return abbreviation;
}
public void setAbbreviation(String abbreviation) {
this.abbreviation = abbreviation;
}
#Override
public String toString() {
return new StringBuilder().append("[name=").append(name).append(", abbreviation=").append(abbreviation).append("]")
.toString();
}
}
Here's the modified example:
import java.util.List;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
public class ListExtractor {
public static void main(String[] args) {
List<Item> items = getItems();
items.forEach(System.out::println);
}
static List<Item> getItems() {
Client restClient = ClientBuilder.newClient();
Response response = restClient.target("https://api.myjson.com/bins/7xq2x").request(MediaType.APPLICATION_JSON).get();
return response.readEntity(new GenericType<List<Item>>() {});
}
static class Item {
private String name;
private String abbreviation;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAbbreviation() {
return abbreviation;
}
public void setAbbreviation(String abbreviation) {
this.abbreviation = abbreviation;
}
#Override
public String toString() {
return new StringBuilder().append("[name=").append(name).append(", abbreviation=").append(abbreviation).append("]")
.toString();
}
}
}
Jersey dependencies (Gradle):
implementation 'org.glassfish.jersey.core:jersey-client:2.25.1'
implementation 'org.glassfish.jersey.media:jersey-media-json-jackson:2.25.1'
implementation 'org.glassfish.jersey.media:jersey-media-jaxb:2.25.1'
Related
How do I get Jackson to treat 'name' as if it had a #JsonProperty annotation?
public class SimpleClass {
private String name;
private String doNotSerialize;
public SimpleClass( #JsonProperty("name") String name ) {
this.name = name;
}
public String getName() {
return name;
}
public int getSum() {
return 1+1;
}
}
The way it is now, I get an error, Unrecognized field "sum", because it treats every getter as a serializable property.
If I add a class annotation:
#JsonAutoDetect( getterVisibility = JsonAutoDetect.Visibility.NONE )
I get an empty string when serializing. I was hoping that Jackson would see the #JsonProperty on the constructor parameter and figure it out.
If I change the class annotation to:
#JsonAutoDetect( getterVisibility = JsonAutoDetect.Visibility.NONE, fieldVisibility = JsonAutoDetect.Visibility.ANY )
Then I get the 'doNotSerialize' field included.
If I set a #JsonCreator on the constructor, and change my autodetect, I still get a blank string:
#JsonAutoDetect( getterVisibility = JsonAutoDetect.Visibility.NONE, fieldVisibility = JsonAutoDetect.Visibility.NONE, creatorVisibility = JsonAutoDetect.Visibility.ANY )
public class SimpleClass {
private String name;
private String doNotSerialize;
#JsonCreator
public SimpleClass( #JsonProperty("name") String name ) {
this.name = name;
}
public String getName() {
return name;
}
public int getSum() {
return 1+1;
}
}
What I'm hoping is that somehow I can tell Jackson to treat all the constructor parameters as serializable fields, and all other fields / setters as non-serializable.
You can use a filter to only serialise getters which have a matching field, e.g.
package org.example;
import com.fasterxml.jackson.annotation.JsonFilter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.PropertyWriter;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import java.io.IOException;
import java.io.StringWriter;
public class App {
#JsonFilter("test")
public static class SimpleClass {
private String name;
private String doNotSerialize;
public SimpleClass(String name ) {
this.name = name;
}
public String getName() {
return name;
}
public int getSum() {
return 1+1;
}
}
public static void main( String[] args ) throws IOException {
SimpleFilterProvider filterProvider = new SimpleFilterProvider();
filterProvider.addFilter("test", new SimpleBeanPropertyFilter() {
#Override
protected boolean include(BeanPropertyWriter writer) {
return super.include(writer);
}
#Override
protected boolean include(PropertyWriter writer) {
String name = writer.getName();
Class clazz = writer.getMember().getDeclaringClass();
try {
clazz.getDeclaredField(name);
return super.include(writer);
} catch (NoSuchFieldException e) {
// ignore
return false;
}
}
});
ObjectMapper mapper = new ObjectMapper();
mapper.setFilterProvider(filterProvider);
StringWriter sw = new StringWriter();
mapper.createGenerator(sw).writeObject(new SimpleClass("foo"));
System.out.println(sw.toString());
}
}
I don't know your full requirements, but this should be a start.
I haven't tried to do what you actually, asked, that is, look at constructor parameters, but that should be possible too.
If you want "sum" to be included in the serializad json but want to ignore it when deserializing you can do:
#JsonIgnoreProperties(ignoreUnknown=true)
public class SimpleClass {
// properties/getters
public int getSum() { return 1+1; }
}
If you want to remove "sum" entirely from the json you can do
#JsonIgnoreProperties({"sum"})
public class SimpleClass {
// properties/getters
public int getSum() { return 1+1; }
}
or
public class SimpleClass {
// properties/getters
#JsonIgnore
public int getSum() { return 1+1; }
}
I want to get the country details from an external api and using Gson to set the data received from the get request to class Country. The problem is that in the response, the currencies key has value which is between [](please see below) and in some cases there is a space between the currencies name values which causes the following error
com.google.gson.stream.MalformedJsonException: Unterminated object at line 1 column 41 path $.currencies[0].name:
"currencies":[{"code":"BGN","name":"Bulgarian lev","symbol":"лв"}]
#RestController
public class CountryController {
#Autowired
private RestTemplate restTemplate;
private static String baseURL = "https://restcountries.com/v2/";
public Object[] getCountryDetails(String countryName){
Object[] countryDetails = restTemplate.getForObject(baseURL+"name/"+countryName+"?fields=name,alpha2Code,alpha3Code,capital,currencies", Object[].class);
return countryDetails;
}
public Country createCountryObject(String countryName) {
String response = Arrays.asList(getCountryDetails(countryName)).get(0).toString();
Gson g = new Gson();
JsonReader reader = new JsonReader(new StringReader(response.trim()));
reader.setLenient(true);
Country country = g.fromJson(reader, Country.class);
return country;
}
#GetMapping("/")
public String getAll(){
Country country = createCountryObject("bulgaria");
return country.getName();
}
}
Country.java:
package country.neighbours.tour.models;
import java.util.List;
public class Country {
private String name;
private String alpha2Code;
private String alpha3Code;
private List<String> borders;
private Object[] currencies;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getBorders() {
return borders;
}
public void setBorders(List<String> borders) {
this.borders = borders;
}
public String getAlpha2Code() {
return alpha2Code;
}
public void setAlpha2Code(String alpha2Code) {
this.alpha2Code = alpha2Code;
}
public String getAlpha3Code() {
return alpha3Code;
}
public void setAlpha3Code(String alpha3Code) {
this.alpha3Code = alpha3Code;
}
public Object[] getCurrencies() {
return currencies;
}
public void setCurrencies(Object[] currencies) {
this.currencies = currencies;
}
}
How can I get only the currency code?
It looks like you are parsing the response twice; once with restTemplate.getForObject, then you convert its result to a String (the result of your toString() call is most likely not JSON) and then you try to parse it a second time with Gson.
In case you only want to use Gson, you can use a TypeToken in the fromJson call to parse the response JSON array:
List<Country> countries = gson.fromJson(..., new TypeToken<List<Country>>() {}.getType());
Maybe someone more familiar with Spring can also explain how to use only RestTemplate.getForObject for this instead of Gson.
I need to write Junit tests in Eclipse and I wanted to know if I am on the right track. I have an Allergey.java and TestAllergey.java. I heard you are not supposed to do tests for getters and setters but it is a requirement and I have no choice. I also did a test for the toString method and am curious if I did that correctly. All the tests passed.
Thanks
package medical.com.medicalApplication.model;
/**
* This class represent the Allergy model in the application
*
*/
public class Allergey {
private String name;
public Allergey(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "Allergy " + name;
}
}
package medicalApplication.model;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import medical.com.medicalApplication.model.Allergey;
public class AllergeyTest {
private Allergey allergy;
#Before
public void setUp() throws Exception {
allergy = new Allergey("Peanut");
}
#Test
public void testGetName() {
String expectedValue = allergy.getName();
String actualValue = "Peanut";
assertTrue(expectedValue.equals(actualValue));
}
#Test
public void testSetName() {
String expectedValue = "Peanut";
allergy.setName(expectedValue);
String actualValue = allergy.getName();
assertTrue(expectedValue.equals(actualValue));
}
#Test
public void testToString() {
assertTrue(allergy.toString().equals("Allergy " + allergy.getName()));
}
}
I've looked all over and found some good answers to my question but i can't get it to work. I found this thread (Parsing single json entry to multiple objects with Gson) but i don't understand where my problem is.
I want to read the file into new Objects (if it's possible with just one then even better but i couldn't find out how).
First the int threads and then the array of tools(where each tool is an Object)
This is my TXT file :
{
"threads": 4,
"tools": [
{
"tool": "gs-driver",
"qty": 35
},
{
"tool": "np-hammer",
"qty": 17
},
{
"tool": "rs-pliers",
"qty": 23
}
]
}
this is my deseralization class, and two of my object classes
import com.google.gson.*;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.List;
public class Deserializer implements JsonDeserializer<ParseJson> {
public ParseJson deserialize(JsonElement json, Type type,
JsonDeserializationContext context) throws JsonParseException {
JsonObject obj = json.getAsJsonObject();
ParseJson test = new ParseJson();
test.setThreads(obj.get("threads").getAsInt());
Gson toolsGson = new Gson();
Type toolsType = new TypeToken<List<ParseTool>>(){}.getType();
List<ParseTool> toolsList = toolsGson.fromJson(obj.get("tools"), toolsType);
test.setTools(toolsList);
return test;
}
}
import java.util.List;
public class ParseJson {
private int threads;
private List<ParseTool> tools;
public void setThreads(int _threads) {
this.threads = _threads;
}
public int getThreads() {
return threads;
}
public void setTools(List<ParseTool> tools) {
this.tools = tools;
}
public List<ParseTool> getTools() {
return tools;
}
}
public class ParseTool {
private int qty;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getQty() {
return qty;
}
public void setQty(int qty) {
this.qty = qty;
}
}
I can get the "threads" but it doesn't parse the array for some reason.
Thanks,
ParseTool contains a propery named name, but the JSON indicates that it's named tool.
You should therefore rename the property name to tool:
public class ParseTool {
private int qty;
private String tool;
public String getTool() {
return tool;
}
public void setTool(String tool) {
this.tool = tool;
}
public int getQty() {
return qty;
}
public void setQty(int qty) {
this.qty = qty;
}
}
This is a follow up question to this question:
Passing custom type query parameter
I got a class which includes this method:
public static MyClass fromString(String json)
{
Gson gson = new Gson();
MyClass user = gson.fromJson(json, MyClass.class);
return user;
}
The full class:
public class MyClass
{
public String name;
public PortalNameEnum portalName;
public PortalUserTypeEnum portalUserType;
public String notes;
public MyClass(String name, PortalNameEnum portalName,
PortalUserTypeEnum portalUserType, String notes)
{
super();
this.portalName = portalName;
this.portalUserType = portalUserType;
this.name = name;
this.notes = notes;
}
public static MyClass fromString(String json)
{
Gson gson = new Gson();
PortalUserInfo user = gson.fromJson(json, PortalUserInfo.class);
return user;
}
public PortalNameEnum getPortalName()
{
return portalName;
}
public void setPortalName(PortalNameEnum portalName)
{
this.portalName = portalName;
}
public PortalUserTypeEnum getPortalUserType()
{
return portalUserType;
}
public void setPortalUserType(PortalUserTypeEnum portalUserType)
{
this.portalUserType = portalUserType;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getNotes()
{
return notes;
}
public void setNotes(String notes)
{
this.notes = notes;
}
}
I got a resource which got a method:
#Path("/myclasscall")
#GET
#UnitOfWork
public String registerPortalUser(#Context HttpServletRequest req, #QueryParam("callback") String callback, #QueryParam("myclass") MyClass recordData) throws Throwable
{ .. }
It seems like the fromString method is not called and the resource method is always null, even though I see in the console the request itself and I do see a string that has been passed. Why is that?
The problem was with the client.
Instead of passing a single parameter called "myclass", he passed all the fields separately. After merging them together into a single Json instance, it was fixed.