问题
I am currently developing with a 3rd party REST API. I am creating objects for their JSON objects being returned by the API. I am following their documentation where it says certain variables will be Strings. Sometimes when there is no String, it will return False. Sometimes I'm expecting a URL and I get False.
How do I handle this?
This is the API in question https://developers.cannabisreports.com/docs/
Strain Object EXAMPLE: https://ghostbin.com/paste/kgeau In the Strain Object, I get an exception when performing a search. Some of the results of the search have booleans instead of strings/url in the bits of code that are commented out.
Sometimes I get this
"genetics": {
"names": false,
"ucpc": false,
"link": false
}
Sometimes I could get this
"genetics": {
"names": "Blueberry x Haze",
"ucpc": "W74AFGH22Z000000000000000 x 9XVU7WJQCD000000000000000",
"link": "https:\/\/www.cannabisreports.com\/api\/v1.0\/strains\/9XVU7PTG2P000000000000000\/genetics"
}
回答1:
When you're in trouble with not a very well designed API, Gson gives you some flexibility while deserializing JSON documents produced by such an API. Despite you have numerous ways to work around this issue (like JsonDeserializer, etc), you mostly like are faced with the false-as-null issue I seem to have seen here already. You can help Gson by marking "wrong" fields:
final class Envelope {
final Genetics genetics = null;
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("genetics", genetics)
.toString();
}
}
final class Genetics {
@JsonAdapter(FalseAsNullTypeAdapterFactory.class)
final String names = null;
@JsonAdapter(FalseAsNullTypeAdapterFactory.class)
final String ucpc = null;
@JsonAdapter(FalseAsNullTypeAdapterFactory.class)
final URL link = null;
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("names", names)
.add("ucpc", ucpc)
.add("link", link)
.toString();
}
}
And this is how the type adapter factory implemented:
final class FalseAsNullTypeAdapterFactory
implements TypeAdapterFactory {
// No worries, Gson will instantiate it itself
private FalseAsNullTypeAdapterFactory() {
}
@Override
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
final TypeAdapter<T> delegateAdapter = gson.getAdapter(typeToken);
return new TypeAdapter<T>() {
@Override
public void write(final JsonWriter out, final T value)
throws IOException {
delegateAdapter.write(out, value);
}
@Override
public T read(final JsonReader in)
throws IOException {
// If the next token is a boolean
if ( in.peek() == JsonToken.BOOLEAN ) {
// and it's true
if ( in.nextBoolean() ) {
// then just report an unexpected `true` literal
throw new MalformedJsonException("Expected a null value indicator as `false`. " + in);
}
// and it's false, then we assume it's a null
return null;
}
// Otherwise read the whole value as a usual
return delegateAdapter.read(in);
}
};
}
}
Once you deserialize the JSON documents you provided in the question, a toString-ed mapping might produce something like this:
Envelope{genetics=Genetics{names=null, ucpc=null, link=null}}
Envelope{genetics=Genetics{names=Blueberry x Haze, ucpc=W74AFGH22Z000000000000000 x 9XVU7WJQCD000000000000000, link=https://www.cannabisreports.com/api/v1.0/strains/9XVU7PTG2P000000000000000/genetics}}
回答2:
Since you already know you will have a boolean or a String, you can get a JsonPrimitive directly.
A primitive value is either a String, a Java primitive, or a Java primitive wrapper type.
Then from the JsonPrimitive instance, you can check if it isBoolean.
Here is how to use it in a small snippet
public static String getURL(JsonObject json, String value){
JsonPrimitive data = json.get(value).getAsJsonPrimitive();
if(data.isBoolean()){
return "Boolean : " + data.getAsBoolean();
} else {
return "String : " + data.getAsString();
}
}
And here is a quick example to validate this logic
public static void main(String[] args) {
String data =
"{"
+ " \"element\" : {"
+ " \"a\":false,"
+ " \"b\":\"foobar\""
+ " }"
+ "}";
JsonObject json = new JsonParser().parse(data).getAsJsonObject();
JsonObject element = json.get("element").getAsJsonObject();
System.out.println(getURL(element, "a"));
System.out.println(getURL(element, "b"));
}
Boolean : false
String : foobar
The json used :
{
"element" :{
"a":false,
"b":"foobar"
}
}
来源:https://stackoverflow.com/questions/50097025/how-to-handle-a-boolean-when-expecting-a-string-in-gson