Serialize object property with JMSSerializerBundle on entity - json

when I serialize my object using jmsserializerbundle I get corrent JSON object but one property is empty (it's object type), the definition of this property looks like this:
/**
* #var stdObject
*
* #ORM\Column(name="searchQueryParams", type="object")
* #Expose
* #Type("stdClass")
*/
private $searchQueryParams;
But even if there is an object on this entity the serializer outpus it like this:
{
"id": 10,
"search_query_params": {},
"created": "2013-07-02T10:31:02+0200"
},
Just an empty object, with is not true. This is value of searchQueryParams in DB:
O:8:"stdClass":2:{s:4:"name";s:8:"Greacja2";s:10:"price_from";s:4:"2000";}

Its a well-known bug of jms serializer. You can store data in database as array and serialize later as array.

Changing #Type to "Array" seemed to worked.

Related

Symfony2 custom json serialization

I am wondering how I can personify the default JSON serialization with JMS on entities.
I have an object A that have a OneToMany relation with an object B.
I expose the object B and attrA from A object.
But instead of having the basic JSON
{'attrA' : 'foo', 'Bs' : {{'attrB' : 'bar'}, {'attrB' : 'baz'}, ...} }
I want to have
{'attrA' : 'foo', 'Bs' : {'bar', 'baz', ...}}
Is it possible to do that?
A way to do this, is to play with serializer's annotations
I assume your value objects looks like this
class Foo
{
/**
* #var string
*/
private $attrA;
/**
* #var ArrayCollection<Bar>
*/
private $bs;
}
class Bar
{
/**
* #var string
*/
private $attrB;
}
Import annotations
First, if you didn't already, you need to import the annotations at the top of your files
use JMS\Serializer\Annotation as Serializer;
Set up a custom getter
By default, JMS serializer gets the property value through reflection. My thoughts go on creating a custom accessor for the serialization.
Note: I assume your bs property is an ArrayCollection. If not, you can use array_map
// Foo.php
/**
* #Serializer\Accessor(getter="getBarArray")
*/
private $bs;
/**
* #return ArrayCollection<string>
*/
public function getBarArray()
{
return $this->getBs()->map(function (Bar $bar) {
return $bar->getAttrB();
});
}
Setting up a custom Accessor(getter) will force the serializer to use the getter instead of the reflection. This way, you can tweak any property value to get it in the format you want.
Result
Serialization of these value objects would result in
{'attrA' : 'foo', 'Bs' : ['bar', 'baz', ...]}

Propel toArray Mechanics in Doctrine?

I was using Propel for a long time and now I want to try Doctrine.
In My Propel days I used PropelObjectCollection::toArray (for a collection) or PropelObject::toArray() for a single record to convert the PropelObject via array to json.
In my company we override the toArray method to store virtual columns in the array and then the json string.
For example:
public function toArray() {
$arr = parent::toArray();
$arr['full_name'] = $this->getFullName(); // full_name isnt part of the table, it's just a getter
return $arr;
}
When I turn this into json i have my full_name property in my json and then in my Extjs store Object (we use extjs).
Now I wanna try doctrine, but doctrine doesn't seem to allow this.
Can i override a function or property in my doctrine class, or can I do this by annotations, is it possible to generate a json with propertys ('first_name', 'last_name', 'full_name') if my Doctrine class only has the properties $first_name, $last_name and no $full_name
or is there a work around to achieve the same?
Thanks for your help
Edit:
I found something in JMSSerializerBundle if you use Annotations:
#VirtualProperty
use JMS\Serializer\Annotation\VirtualProperty;
at the top of my Doctrine Entity File and an example method
/**
*
* #VirtualProperty
* #return string
*/
public function getFullName() {
return $this->getName(). " mylastname";
}
my json then contains the virtual property full_name

deserialize lazylist using jackson

I have a object which uses a org.apache.commons.collections.list.LazyList for one of its fields, which is serialized ti JSON. The JSON looks like this:
"myObject": ["org.apache.commons.collections.list.LazyList", [
{
"attr1": "asdasd",
"attr2": 1234
}
]],
The object field looks like this:
List<MyObject> myObject = ListUtils.lazyList(new ArrayList(), {new MyObject()} as Factory)
However trying to deserialize the above JSON using a Jackson ObjectMapper fails, since it can't find a default constructor for a LazyList - which makes sense. But how can I specify how this field can be deserialized?
Error message:
No default constructor for [collection type; class org.apache.commons.collections.list.LazyList, contains [simple type, class foo.bar.MyObject]]
Bounty-constraints:
To collect the bounty, this question needs to be answered using a custom jackson deserializer - the custom deserializer must not be field specific! Hence no solution using custom implementations of a LazyList for a specific type will answer this question adequately.
The solution below worked on both List and Map collection objects, it might also work on yours.
#JsonDeserialize(contentAs=MyObject.class)
private List<MyObject> myObject = ListUtils.lazyList(new ArrayList(), {new MyObject()} as Factory);

JacksonProviderProxy writing out null values in json output

I have a simple POJO class that extends another simple POJO class. I am using the com.sun.jersey.json.impl.provider.entity.JacksonProviderProxy to marshall the properties in these POJO classes to JSON. However, when I set some of the properties to the POJO as null, then it outputs those properties as the string null instead of not outputting it at all.
for eg.
{
Person:
[{
"firstName":"John"
"lastName":"null"
}]
}
instead of:
for eg.
{
Person:
[{
"firstName":"John"
}]
}
Different options are available for suppressing serialization of properties with null values, depending on the version of Jackson in use, and whether the ObjectMapper can be directly configured.
With Jackson 1.1+, with direct access to configure the ObjectMapper, you could just call setSerializationInclusion(Include.NON_NULL).
Alternatively, you could annotate the (class) type that has the properties, for which null properties serialization is to be suppressed, with #JsonSerialize(include=Inclusion.NON_NULL).
With Jackson 2+, instead of the #JsonSerialize annotation, use #JsonInclude(Include.NON_NULL).

Jackson JSON to Java mapping for same attrubute with different data type

I have a JSON object which I don't have control of and want to map it to a Java object which is pre-created.
There is one attribute in the JSON object which can be a URL or it could be a JSONArray.
Class SomeClass {
private URL items;
public URL getURL() {
return items;
}
public void setURL(URL url) {
this.items = url;
}
}
Below is the JSON:
Case A:
{
...
items: http://someurl.abc.com/linktoitems,
...
}
OR
Case B
{
...
items: [
{ "id": id1, "name": name1 },
{ "id": id2, "name": name2 }
]
...
}
If i create the POJO to map for Case A, Case B fails and vice versa. In short, is there a way to map the JSON attribute to the POJO field with different data types? In that case I will create two separate fields in the POJO named,
private URL itemLink;
private Item[] itemList;
It depends on exact details, but if what you are asking is if it is possible to map either JSON String or JSON array into a Java property, yes this can be done.
Obvious way would be to define a custom deserializer which handles both kinds of JSON input.
But it is also possible to define Java type in such a way that it can be constructed both by setting properties (which works from JSON Object) and have a single-String-arg constructor or static single-String-arg factory method marked with #JsonCreator.
Yet another possibility is to use an intermediate type that can deserialized from any JSON: both java.lang.Object and JsonNode ("JSON tree") instances can be created from any JSON. From this value you would need to do manual conversion; most likely in setter, like so:
public void setItems(JsonNode treeRoot) { .... }
What will not work, however, is defining two properties with the same name.
One thing I don't quite follow is how you would convert from List to URL though. So maybe you actually do need two separate internal fields; and setter would just assign to one of those (and getter would return value of just one).