I am using Play Framework to expose REST API, which returns some JSON objects.
To simplify the API usage, I would like to return a "calculated" field in the response.
Unfortunately, in my tests, while FlexJson does not ignore the transient model fields completely, but always sets them to 'null'.
More details:
In the model class, I define:
#Transient
public String currencyName;
The only constructor of the class set the value to "dollar" (for debugging purposes):
this.currencyName = "dollar";
When serializing the class using FlexJson, when the 'currencyName' field is not specified in the include/ exclude - the result always looks like:
"currencyName":null
Any idea what got wrong, and how to get the field value serialized into JSON?
Thanks in advance.
By definition if your field is transient it will not be serialized. Perhaps this field should not be transient in your application if the state matters.
Related
I'm new to Typescript and I encountered a JSON deserializing problem.
Consider this class:
class Product {
public id!: number;
public get calculatedProperty() : string {
return "Test";
};
};
As you can see calculatedProperty is a runtime calculated property.
Also, consider that I deserialize a JSON string into my object in this way:
var jsonData = '{ "id": 2 }';
let deserialized = JSON.parse(jsonData) as Product;
The problem comes now:
This call console.log(deserialized.id); returns correctly 1.
This call console.log(deserialized.calculatedProperty); returns undefined!
I really don't understand way. It seems that as Product doesn't really create a Product object, because If I directly invoke the constructor, new Product, the calculated property exists.
What am I doing wrong with the JSON deserialization?
Thanks!
TypeScript's job is only to perform type checking during development and make sure we don't make careless mistakes. At the end of the day, all it does is just compiling the script and transform it into good old JavaScript. Therefore, any TypeScript syntax are not applied in runtime.
In other words, type assertions are removed in runtime.
There are also several warnings in the documentation about this:
Like a type annotation, type assertions are removed by the compiler and won’t affect the runtime behavior of your code.
Reminder: Because type assertions are removed at compile-time, there is no runtime checking associated with a type assertion. There won’t be an exception or null generated if the type assertion is wrong.
Besides, the as keyword does not instantiate a constructor. It merely provides a type information (which will be removed during compile-time). The only way we can instantiate a constructor and access its instance properties/methods is through the new keyword.
The JSON.parse method isn't really for converting json into a class rather than an object.
To solve your issue you could potentially convert the json into an object like this:
let deserializedObject = JSON.parse(jsonData) as Object;
and after that you could assign the object to a class like that:
let deserialized = Object.assign(new Product(), deserializedObject);
Note that I have not tested this yet, but it should work.
Also this is fine for simple objects, but not for objects with complex hierarchy.
Look into class-transformer for more information. https://github.com/typestack/class-transformer
I try to realize database access decorator based on Expression types. So, I've already tried many different json serializing libraries, started from Newtonsoft Json till DataContractJsonSerializator and etc.
1) Most of serializators crash on Expression type serialization (including System.Text.Json.Serialization).
2) Newtonsoft.JsonSerializer successfully serialize Expression<Func<User, bool>> test = e => e.Id == sameUser.Id, where User is the class like:
public class User
{
public Guid Id { get; set; }
public string Fullname { get; set; }
}
and sameUser is an object of User class.
But Newtonsoft.JsonSerializer produces string of ~169-200 millions symbols. I don't know does Newtonsoft.JsonSerializer correctly deserialize this json of the other side becauseof the size. Ofcourse, I've tried to use different serializing options.
3) ServiceStack.Text.JsonSerializer successfully serialize Expression<Func<User, bool>> test = e => e.Id == sameUser.Id with normal json size (approx 2-3 thousands symbols), but on the deserialization Expression.Body always null after deserialization (and this really strange - serialized json has it well-serialized).
4) Serialize.Linq successfully passed the test.
I want to understand, what the reason of this strange behavior of main serializers like Newtonsoft, ServiceStack, Microsoft, etc?
P.S. I'ven't tested protobuf-net and MessagePack yet, I'll do this soon,but think they have the same troubles with Expression class object serialization/deserialization.
Expression has cyclical dependencies an non serializable references that is not suitable for serialization. If you want to serialize the debug string representation of an Expression do that in your code and serialize the string, don’t expect serialization libraries to attempt to serialize a non-serializable class that’s impossible to deserialize.
If you want to serialize code, send raw source code and use Roslyn or Code DOM to execute the source code received, you’ll need to validate any untrusted user code for potential security vulnerabilities or unwanted behavior before evaluating it.
I'm passing a Laravel Model's dataset to a vuejs2 component via ajax/ axiom and rendering it fine.
However, there is a JSON column in the model which stores a valid json object, the data could look like so: {'key':'value'} and it's worth noting that I'm working with it without issue in Laravel Controllers etc thanks to a Mutator on the Model ( protected $casts = [ 'the_json_column' => 'array']; )
When I pass this model to vuejs via axiom / ajax all of the properties in the array behave as usual, I can iterate over them and render them in the vuejs2 component DOM.
Until I interact with 'the_json_column' which despite Laravel's mutator is being passed to vuejs2 as a string, e.g. "{'key':'value'}"
Is there a more elegant way than doing a JSON.parse(data.the_json_column).key in my vuejs2 component every time I want to interact with the JSON column data?
The solution I've gone with is decoding the data property manually in the VueJS2 template,
e.g. JSON.parse(data.key_which_is_actually_json).property_in_the_object
Any laravel based code (accessors, mutators etc) will fail when the property is transferred to VueJS2 component over HTTP as VueJS2 isn't smart enough to check properties in data receive and decode them.
VueJS2 seems to only decode the top level of properties in data received.
You may create your own Accessor and then convert the column to an array manually before retrieving the model.
public function getTheJsonColumnAttribute($value)
{
return json_decode($value, true);
}
While it may seem laravel simply treated that column as a mere 'string' value when coming out, you can further validate that there is indeed a conversion.
I'm trying to change the (de)serialization of a list in one of my classes.
the objects in the list shall be serialised as int (their jpa id) and deserialised accordingly. serialization is simple.
for the deserialization i have a class that can translate the id into the object if id and class are known.
How do i get the necessary class from jackson? all default jackson serialisers have a constructor like this: protected StdDeserialiser(Class<?> vc) so the information is present somewhere.
is there a way to access it during deserialisation?
or before the deserialiser is constructed by jackson?
or inside the HandlerInstantiator?
I only want to overwrite the default deseriliser for certain references so i can't just write a provider or a custom module.
I made it work from inside the deserializer with the help of the ContextDeserializer interface as this supplies the deserializer with the target property.
public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException {
Class<?> vc = null;
if (property.getType().isCollectionLikeType()) {
vc = property.getType().getContentType().getRawClass();
} else {
vc = property.getType().getRawClass();
}
return new ResourcePathDeserializer(vc, converter);
}
This solution is not perfect as I only get the raw class of the return type or the generic (which might be a parent class or an interface) but that is enough for my requirements.
It would be better if I could access the "real" class that was resolved by Jackson, but for me this works.
First of all, there is nothing fancy about writing a Module: it is just a way for plugging things in, like custom (de)serializers. So no need to avoid that. And you will most like need to write a module to do what you want.
In general it is not a good idea to try to create "universal" serializers or deserializers, and it will probably run into problem. But it depends on what exactly you are trying to do.
Type information will either be:
Implicit from context: you are writing a (de)serializer for type T, and register it for it, so that's your type
Passed by Jackson when (de)serializer is being constructed, via Module interface: modules are asked if they happen to have a (de)serializer for type T. SimpleModule will only use basic Class-to-impl mapping (that's where "simple" comes from); but full custom Module has access to incoming type.
But I don't know if above will work for your use case. Type information must be available from static type (declared content type for the list).
My server returns a list of objects in JSON. They might be Cats or Dogs, for example.
When I know that they'll all be Cats, I can set the AutoBeanCodex to work easily. When I don't know what types they are, though... what should I do?
I could give all of my entities a type field, but then I'd have to parse each entity before passing it to the AutoBeanCodex, which borders on defeating the point. What other options do I have?
Just got to play with this the other day, and fought it for a few hours, trying #Category methods and others, until I found this: You can create a property of type Splittable, which represents the underlying transport type that has some encoding for booleans/Strings/Lists/Maps. In my case, I know some enveloping type that goes over the wire at design time, and based on some other property, some other field can be any number of other autobeans.
You don't even need to know the type of the other bean at compile time, you could get values out using Splittable's methods, but if using autobeans anyway, it is nice to define the data that is wrapped.
interface Envelope {
String getStatus();
String getDataType();
Splittable getData();
}
(Setters might be desired if you sending data as well as recieving - encoding a bean into a `Splittable to send it in an envelope is even easier than decoding it)
The JSON sent over the wire is decoded (probably using AutoBeanCodex) into the Envelope type, and after you've decided what type must be coming out of the getData() method, call something like this to get the nested object out
SpecificNestedBean bean = AutoBeanCodex.decode(factory,
SpecificNestedBean.class,
env.getData()).as();
The Envelope type and the nested types (in factory above) don't even need to be the same AutoBeanFactory type. This could allow you to abstract out the reading/writing of envelopes from the generic transport instance, and use a specific factory for each dataType string property to decode the data's model (and nested models).