IllegalArgumentException: Deserializing generated objects with #JsonString annotation - java

Long values in Objects generated by Cloud Endpoints are annotated with #JsonString. This causes a IllegalArgumentException when deserializing those Objects using a GsonFactory.
This is the stacktrace:
Caused by: java.lang.IllegalArgumentException: number type formatted as a JSON number cannot use #JsonString annotation [key updated, field private java.lang.Long com.google.api.services.timetable.model.Lesson.updated]
at com.google.common.base.Preconditions.checkArgument(Preconditions.java:119)
at com.google.api.client.json.JsonParser.parseValue(JsonParser.java:599)
at com.google.api.client.json.JsonParser.parse(JsonParser.java:350)
at com.google.api.client.json.JsonParser.parseValue(JsonParser.java:586)
at com.google.api.client.json.JsonParser.parse(JsonParser.java:289)
at com.google.api.client.json.JsonParser.parse(JsonParser.java:266)
at com.google.api.client.json.JsonFactory.fromString(JsonFactory.java:207)
Example code to produce the Exception:
GsonFactory gsonFactory = new GsonFactory();
Lesson lesson = new Lesson();
lesson.setUpdated(2);
String json = gsonFactory.toString(lesson);
gsonFactory.fromString(json, Lesson.class);
Original discusssion https://groups.google.com/d/msg/endpoints-trusted-testers/-/_TKGoruZVt0J

The reason why this exception occurs is because the Java client library expects all long integers to be quoted (aka strings), because JavaScript can't handle 64-bit integer precision correctly. There's a known issue where the Python SDK won't correctly serialize 64-bit integers as strings. I'm not sure where you're getting the JSON from, exactly, but if it's in user code, you need to make sure you also have 64-bit integers quoted properly.

Related

Compile time check while passing values to a function in Kotlin Android

I am taking a JSON file as input for a class and parsing the values using gson through respective data classes.
I want to call a function that takes a String value as an argument.
The string value allowed is decided from the values parsed from JSON file. Can I somehow check for that string value passed to the function at compile-time & give an error at compile-time?
Or If I can allow only certain values in the argument for the function based on the values from JSON
Detailed Explanation of use case:
I am building a SDK in which a the person using sdk inputs json String. The json is standardised and is parsed in my code.
{
"name": "Test",
"objects": [
{
"name": "object1",
"type": "object1"
}
]
}
Here name values and other values may vary based on the input by the developer using it but key remains same. But we need to call a function using the value in objects name parameter.
fun testMethod(objectName:String)
So developer calls the testMethod as testMethod(object1).
I need to validate object1 parameter based on json but is there any way possible restricting the test method parameter to object1 only & give error at compile time if the developer calls testMethod(obj1)
Right now I parse JSON & have checks inside the testMethod()
Sure it's possible to do, but somehow in different way, that you described. First of all, as you already mentioned this behavior could be done easily. For this purpose we have Objects.requireNotNull() or Guava.Preconditions(). At the same way you can define you checking but this will work on runtime only.
To do in compile time, you need to create Annotation Preprocessor. The same, as did in different libraries, and one of them, could be Lombok, with their NotNull and Nullable. Android annotation just provide mark and bound for IDE warning, but in their case they adding NotNull checking and throw exception for every annotation usage during compile time.
It's not an easy way, but it's what you are looking for.
No, it's impossible check it in compiler time. It's string handling, as numeric calculation.
In my app, I convert string to JSON and JSON to string, passing class descriptor. My aim is record JSON string in a text file to load in SQLite database. This code I've run in my desktop computer not in Android.
data class calcDescr (
...
)
val calc = CalcDescr(...)
// toJson: internal Kotlin data to JSON
val content = Gson().toJson(calc)
//==================
// Testing validity
// ================
// fromJson: JSON to internal Kotlin data.
// It needs pass the class descriptor. Uses *Java* token, but it's *Kotlin*
var testModel = Gson().fromJson(content, CalcDescr::class.java)
// toJson: internal Kotlin data to JSON again
var contentAgain = Gson().toJson(testModel)
// shoul be equal!
if (content == contentAgain) println("***ok***")
In my file, I write the variable content in a file

Jackson: Object to String via writeValueAsString: NPE

Im attempting to convert a Java Object into JSON using the Jackson parser. The original object comes to me via protobuf and contains some #annotations specific to Jackson.
When I call String jsonView = objectMapper.writeValueAsString(values);
I get this exception. The object doesn't contain any recursive values so I'm not clear why Im seeing this error (or even this code path).
ObjectMapper is configured with: objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); (although removing it doesn't seem to change anything)
java.lang.NullPointerException: null
at com.fasterxml.jackson.databind.type.ResolvedRecursiveType.equals(ResolvedRecursiveType.java:103)
at com.fasterxml.jackson.databind.type.TypeBindings$AsKey.equals(TypeBindings.java:458)
at java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:940)
at com.fasterxml.jackson.databind.util.LRUMap.get(LRUMap.java:68)
at com.fasterxml.jackson.databind.type.TypeFactory._fromClass(TypeFactory.java:1211)
at com.fasterxml.jackson.databind.type.TypeFactory._fromParamType(TypeFactory.java:1384)
at com.fasterxml.jackson.databind.type.TypeFactory._fromAny(TypeFactory.java:1154)
at com.fasterxml.jackson.databind.type.TypeFactory._resolveSuperInterfaces(TypeFactory.java:1298)
at com.fasterxml.jackson.databind.type.TypeFactory._fromClass(TypeFactory.java:1243)
at com.fasterxml.jackson.databind.type.TypeFactory._fromAny(TypeFactory.java:1150)
at com.fasterxml.jackson.databind.type.TypeFactory._resolveSuperInterfaces(TypeFactory.java:1298)
at com.fasterxml.jackson.databind.type.TypeFactory._fromClass(TypeFactory.java:1247)
at com.fasterxml.jackson.databind.type.TypeFactory._fromAny(TypeFactory.java:1150)
at com.fasterxml.jackson.databind.type.TypeFactory.constructType(TypeFactory.java:618)
at com.fasterxml.jackson.databind.cfg.MapperConfig.constructType(MapperConfig.java:290)
at com.fasterxml.jackson.databind.cfg.MapperConfig.introspectClassAnnotations(MapperConfig.java:320)
at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.removeIgnorableTypes(BeanSerializerFactory.java:714)
at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.findBeanProperties(BeanSerializerFactory.java:573)
at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.constructBeanSerializer(BeanSerializerFactory.java:390)
at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.findBeanSerializer(BeanSerializerFactory.java:273)
at com.fasterxml.jackson.databind.ser.BeanSerializerFactory._createSerializer2(BeanSerializerFactory.java:225)
at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.createSerializer(BeanSerializerFactory.java:159)
at com.fasterxml.jackson.databind.SerializerProvider._createUntypedSerializer(SerializerProvider.java:1272)
at com.fasterxml.jackson.databind.SerializerProvider._createAndCacheUntypedSerializer(SerializerProvider.java:1243)
at com.fasterxml.jackson.databind.SerializerProvider.findValueSerializer(SerializerProvider.java:535)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.resolve(BeanSerializerBase.java:332)
at com.fasterxml.jackson.databind.ser.SerializerCache.addAndResolveNonTypedSerializer(SerializerCache.java:174)
at com.fasterxml.jackson.databind.SerializerProvider._createAndCacheUntypedSerializer(SerializerProvider.java:1254)
at com.fasterxml.jackson.databind.SerializerProvider.findValueSerializer(SerializerProvider.java:535)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.resolve(BeanSerializerBase.java:332)
at com.fasterxml.jackson.databind.ser.SerializerCache.addAndResolveNonTypedSerializer(SerializerCache.java:174)
at com.fasterxml.jackson.databind.SerializerProvider._createAndCacheUntypedSerializer(SerializerProvider.java:1254)
at com.fasterxml.jackson.databind.SerializerProvider.findValueSerializer(SerializerProvider.java:535)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.resolve(BeanSerializerBase.java:332)
at com.fasterxml.jackson.databind.ser.SerializerCache.addAndResolveNonTypedSerializer(SerializerCache.java:197)
at com.fasterxml.jackson.databind.SerializerProvider._createAndCacheUntypedSerializer(SerializerProvider.java:1233)
at com.fasterxml.jackson.databind.SerializerProvider.findValueSerializer(SerializerProvider.java:499)
at com.fasterxml.jackson.databind.SerializerProvider.findTypedValueSerializer(SerializerProvider.java:697)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:270)
at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:3672)
at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3048)
Fixed in latest versions (see 2.8.1 or above):
https://github.com/FasterXML/jackson-databind/issues/1302

How to validate number format TextField in wicket?

In my maven-wicket (6.10) application I have a TextField, which has an Integer type property model. I want to set a maximum length for numberts to type into this TextField. (for example the user should write maximum 2 characters to the "age" text field)
I have tried this code:
add(new TextField<>("age",new PropertyModel<(personModel,"age"))
.add(StringValidator.maximumLength(2)));
//age is an Integer value from a Person class, personModel is "IModel<Person>" type
but I got this exception:
java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.String
at org.apache.wicket.validation.validator.StringValidator.getValue(StringValidator.java:87)
at org.apache.wicket.validation.validator.StringValidator.getValue(StringValidator.java:59)
at org.apache.wicket.validation.validator.AbstractRangeValidator.validate(AbstractRangeValidator.java:107)
at org.apache.wicket.markup.html.form.FormComponent.validateValidators(FormComponent.java:1523)
So if the property model is not string type, I cannot use StringValidator. I have found examples, which use NumberValidator (validators), but I cannot resolve NumberValidator. I have only these validators in the source:
How could I use number validator? Or am I missing something, maybe form the pom.xml's dependencies for wicket?
The problem you are facing is related to the way Wicket works. First it converts input text into a model object and then it performs validation.
Thus, you have to use RangeValidator instead of StringValidator
IModel<Integer> model =
new PropertyModel<Integer>(personModel, "age");
Component ageField = new TextField<Integer>("age", model);
add(ageField).add(RangeValidator.<Integer>range(0, 99));
Note I've changes Long to Integer as I believe saving age as Long is not practical.
Also note that link to NumberValidator is for Wicket 1.4, while you are using Wicket 6. Wicket 6 is a large API change comparing to previous versions.
For future reference please have a look at NumberTextField<N>
In Op's case, you could do more easily like:
IModel<Integer> model = new PropertyModel<Integer>(personModel, "age");
add(new NumberTextField<Integer>("age", model).setMinimum(0).setMaximum(99));

Detect type of JSON attribute

JSON:
{"attribute1":11, "attribute2":"string atribute"}
I want to detect what kind of type are attribute1 and attribute2:
attribute1 is integer
attribute2 is string
jsonObject.getAttributeType("attribute2"); // should output: string/integer/boolean.
It was very easy to achieve in PHP or OBJC. Suggestions?
(I'm assuming that the Android for the org.json package is that same as you can find on the json.org site ... here.)
The only method on a JSONObject that will give you the underlying value ... without coercing it ... is JSONObject.get(name). If name is known, the result is the object that represents the value internally. I haven't done a comprehensive trawl of the code, but I think it can only be one of the following types:
Boolean, Long, Double, String, JSONArray, JSONObject
You should be able to discriminate these using instanceof.
But should be asking yourself if this is the right thing to do. The normal way to deal with JSON object attributes via the JSONObject API is to use the methods that coerce them into the type that you expect. In most cases, it doesn't matter if a number is sent as 42 or 42.0 or "42" ... and it is best not to be picky if the intent is easy to determine.
Another solution you can use the jackson library to do this,
import com.fasterxml.jackson.databind.JsonNode;
import com.github.fge.jackson.JsonLoader;
//Defining the JSON object
JSON json = {"attribute1":11, "attribute2":"string atribute"};
//Get the needed attribute
String value = json.get("attribute1");
//Convert the attribute to JsonNode
JsonNode value = JsonLoader.fromString(value);
//Then you can check type as below
value.isObject();
value.isArray();
value.isDouble();
value.isTextual();
value.isInt()

Python 3.x: Java valueOf() equivalent in Python 3.x

Whilest learning Python 3 and converting some of my code from Java to Python 3.3 I came across a small problem I haven't been able to fix.
In Java I have this code (just dummy code to make it smaller):
public enum Mapping {
C11{public int getMapping(){ return 1;}},
C12{public int getMapping(){ return 2;}},
public abstract int getMapping();
}
String s = "C11";
System.out.println(Mapping.valueOf(s))
Works fine and prints the requisted '1'
Trying to do this in Python doesn't work that easy (yet). I tried to imitate an Enum with:
class Mapping:
C11=1
C12=2
s = 'C11'
print(Mapping.Mapping.(magic should happen here).s)
Unfortunately I have no idea how to convert a string to an attribute to be called like that (or something similar).
I need this because I have a HUGE list in the class Mapping and need to convert seemingly random words read from a text file to an integer mapping.
You are looking for getattr:
>>> getattr(Mapping, s)
1
From the documentation:
getattr(object, name[, default])
Return the value of the named attribute of object. name must be a string. If the string is the name of one of the object’s attributes, the result is the value of that attribute. For example, getattr(x, 'foobar') is equivalent to x.foobar. If the named attribute does not exist, default is returned if provided, otherwise AttributeError is raised.
Use getattr:
class Mapping:
C11=1
C12=2
print(getattr(Mapping, 'C11')) # prints 1

Categories

Resources