Discussion:
JMSSerializer - @XmlList misconfiguration for arrays containing multiples class types
Rémi ALVADO
2012-04-11 12:43:53 UTC
Permalink
Hi,

I'm currently trying to use JMSSerializer to read an XML feed coming from a
solr interface. This feed looks something like :

<doc>
<str name="id">foo</str>

<str name="name">bar</str>
<int name="occ">123</int>

<int name="price">9</int>

</doc>


So, basically, the "doc" element contains a list of "str" elements and a list of "int" elements. "str" and "int" are basically the same except that "int" should contain a text node that is an integer where "str" text node can be any string. Pretty common solr practice so far :)

I've created an interface "SimpleType" that is implemented by both "String" and "Integer" classes. "Integer" class looks like ("String" is nearly the same) :


<?php
namespace MyCompanyBundle\Model\SolrResults;

use JMS\SerializerBundle\Annotation\AccessType,
JMS\SerializerBundle\Annotation\XmlRoot,
JMS\SerializerBundle\Annotation\Type,
JMS\SerializerBundle\Annotation\XmlAttribute,
JMS\SerializerBundle\Annotation\SerializedName,
JMS\SerializerBundle\Annotation\Since,
JMS\SerializerBundle\Annotation\XmlValue;

/**
* @AccessType("public_method")
* @XmlRoot("int")
*/
class Integer implements SimpleType {

/**
* @Type("string")
* @XmlAttribute
* @SerializedName("name")
* @Since("1")
*/
protected $name = null;

/**
* @Type("integer")
* @XmlValue
* @Since("1")
*/
protected $value = null;

function __construct($name = null, $value = null) {
$this->setName($name);
$this->setValue($value);
}

public function getName() {
return $this->name;
}

public function setName($name) {
$this->name = $name;
}

public function getValue() {
return $this->value;
}

public function setValue($value) {
$this->value = $value;
}
}

?>


My issue is with the "Document" class that map the "doc" element. I've tried to use a $simpleTypes array to store all my SimpleType elements (whatever there are String or Integer) and to use some JMS Annotations to describe it as an inline XmlList but I can't manage to get it work. Here an implementation of the "Document" class :


<?php
namespace MyCompanyBundle\Model\SolrResults;

use JMS\SerializerBundle\Annotation\AccessType,
JMS\SerializerBundle\Annotation\Accessor,
JMS\SerializerBundle\Annotation\XmlRoot,
JMS\SerializerBundle\Annotation\Type,
JMS\SerializerBundle\Annotation\XmlAttribute,
JMS\SerializerBundle\Annotation\SerializedName,
JMS\SerializerBundle\Annotation\Since,
JMS\SerializerBundle\Annotation\XmlValue,
JMS\SerializerBundle\Annotation\XmlList,
JMS\SerializerBundle\Annotation\Exclude;

/**
* @AccessType("public_method")
* @XmlRoot("doc")
*/
class Document {

/**
* @Type("array<MyCompanyBundle\Model\SolrResults\SimpleType>")
* @XmlList(inline = true)
* @Accessor(getter="getSimpleTypes")
* @Since("1")
*/
protected $simpleTypes = array();

function __construct($simpleTypes = null) {
$this->setSimpleTypes($simpleTypes);
}

public function getSimpleTypes() {
return $this->simpleTypes;
}

public function setSimpleTypes($simpleTypes) {
if (!is_array($simpleTypes)) $simpleTypes = array();

$this->simpleTypes = $simpleTypes;
}
}

?>


So far, what I get when I try to serialize my object is :

<?xml version="1.0" encoding="UTF-8"?>
<doc>
<entry name="foo1"><![CDATA[bar]]></entry>
<entry name="foo2">12345</entry>
</doc>

which is not what I'm expecting. I know that I could use @XmlList(inline =
true, entry= "xxx") where xxx would be nodeName for any elements in my
$simpleTypes array but since I can have different class in this array, I'd
prefer that JMSSerializer can use the XMLRoot value defined in my "Integer"
and "String" classes.
Is there any way to do that or should I have two arrays, one for String
elements and the other for Integer ones ?

Thanks.

Rémi
--
If you want to report a vulnerability issue on symfony, please send it to security at symfony-project.com

You received this message because you are subscribed to the Google
Groups "Symfony2" group.
To post to this group, send email to symfony2-/***@public.gmane.org
To unsubscribe from this group, send email to
symfony2+unsubscribe-/***@public.gmane.org
For more options, visit this group at
http://groups.google.com/group/symfony2?hl=en
Johannes Schmitt
2012-04-11 15:00:46 UTC
Permalink
Currently, you need two arrays, but feel free to create an issue or submit
a PR for supporting mixed collections.

Johannes
Post by Rémi ALVADO
Hi,
I'm currently trying to use JMSSerializer to read an XML feed coming from
<doc>
<str name="id">foo</str>
<str name="name">bar</str>
<int name="occ">123</int>
<int name="price">9</int>
</doc>
So, basically, the "doc" element contains a list of "str" elements and a list of "int" elements. "str" and "int" are basically the same except that "int" should contain a text node that is an integer where "str" text node can be any string. Pretty common solr practice so far :)
<?php
namespace MyCompanyBundle\Model\SolrResults;
use JMS\SerializerBundle\Annotation\AccessType,
JMS\SerializerBundle\Annotation\XmlRoot,
JMS\SerializerBundle\Annotation\Type,
JMS\SerializerBundle\Annotation\XmlAttribute,
JMS\SerializerBundle\Annotation\SerializedName,
JMS\SerializerBundle\Annotation\Since,
JMS\SerializerBundle\Annotation\XmlValue;
/**
*/
class Integer implements SimpleType {
/**
*/
protected $name = null;
/**
*/
protected $value = null;
function __construct($name = null, $value = null) {
$this->setName($name);
$this->setValue($value);
}
public function getName() {
return $this->name;
}
public function setName($name) {
$this->name = $name;
}
public function getValue() {
return $this->value;
}
public function setValue($value) {
$this->value = $value;
}
}
?>
<?php
namespace MyCompanyBundle\Model\SolrResults;
use JMS\SerializerBundle\Annotation\AccessType,
JMS\SerializerBundle\Annotation\Accessor,
JMS\SerializerBundle\Annotation\XmlRoot,
JMS\SerializerBundle\Annotation\Type,
JMS\SerializerBundle\Annotation\XmlAttribute,
JMS\SerializerBundle\Annotation\SerializedName,
JMS\SerializerBundle\Annotation\Since,
JMS\SerializerBundle\Annotation\XmlValue,
JMS\SerializerBundle\Annotation\XmlList,
JMS\SerializerBundle\Annotation\Exclude;
/**
*/
class Document {
/**
*/
protected $simpleTypes = array();
function __construct($simpleTypes = null) {
$this->setSimpleTypes($simpleTypes);
}
public function getSimpleTypes() {
return $this->simpleTypes;
}
public function setSimpleTypes($simpleTypes) {
if (!is_array($simpleTypes)) $simpleTypes = array();
$this->simpleTypes = $simpleTypes;
}
}
?>
<?xml version="1.0" encoding="UTF-8"?>
<doc>
<entry name="foo1"><![CDATA[bar]]></entry>
<entry name="foo2">12345</entry>
</doc>
= true, entry= "xxx") where xxx would be nodeName for any elements in my
$simpleTypes array but since I can have different class in this array, I'd
prefer that JMSSerializer can use the XMLRoot value defined in my "Integer"
and "String" classes.
Is there any way to do that or should I have two arrays, one for String
elements and the other for Integer ones ?
Thanks.
Rémi
--
If you want to report a vulnerability issue on symfony, please send it to
security at symfony-project.com
You received this message because you are subscribed to the Google
Groups "Symfony2" group.
To unsubscribe from this group, send email to
For more options, visit this group at
http://groups.google.com/group/symfony2?hl=en
--
If you want to report a vulnerability issue on symfony, please send it to security at symfony-project.com

You received this message because you are subscribed to the Google
Groups "Symfony2" group.
To post to this group, send email to symfony2-/***@public.gmane.org
To unsubscribe from this group, send email to
symfony2+unsubscribe-/***@public.gmane.org
For more options, visit this group at
http://groups.google.com/group/symfony2?hl=en
Rémi ALVADO
2012-04-12 07:19:31 UTC
Permalink
OK thanks :(
I've tried to use two arrays with a code looking like the following but it
does not work either :

/**
* @Type("array<MyCompanyBundle\Model\SolrResults\String>")
* @XmlList(inline = true, entry = "string")
* @Since("1")
*/
protected $strings = array();


/**
* @Type("array<MyCompanyBundle\Model\SolrResults\Integer>")
* @XmlList(inline = true, entry = "integer")
* @Since("1")
*/
protected $integer = array();


JMSSerializer told me that I couldn't have two elements tagged as XmlValue.
I suppose that defining an xmlList as "inline" implies that the attribute
is an XmlValue.

Finally, to make it work, I had to forget about the "int" nodes and only
deal with "str" nodes. It works for now since we are not using any integer
attribute on our backend so far but I don't know how long it will last :(
I'll try to find some time to dig into JMSSerializer source code and submit
a PR with this new feature.
Thanks anyway for your answer and for all your bundles (I love the
JMSDIExtraBundle : services.{yml\xml} are a a pain in the ass in term of
code readibility)


Rémi
Post by Johannes Schmitt
Currently, you need two arrays, but feel free to create an issue or submit
a PR for supporting mixed collections.
Johannes
Post by Rémi ALVADO
Hi,
I'm currently trying to use JMSSerializer to read an XML feed coming from
<doc>
<str name="id">foo</str>
<str name="name">bar</str>
<int name="occ">123</int>
<int name="price">9</int>
</doc>
So, basically, the "doc" element contains a list of "str" elements and a list of "int" elements. "str" and "int" are basically the same except that "int" should contain a text node that is an integer where "str" text node can be any string. Pretty common solr practice so far :)
<?php
namespace MyCompanyBundle\Model\SolrResults;
use JMS\SerializerBundle\Annotation\AccessType,
JMS\SerializerBundle\Annotation\XmlRoot,
JMS\SerializerBundle\Annotation\Type,
JMS\SerializerBundle\Annotation\XmlAttribute,
JMS\SerializerBundle\Annotation\SerializedName,
JMS\SerializerBundle\Annotation\Since,
JMS\SerializerBundle\Annotation\XmlValue;
/**
*/
class Integer implements SimpleType {
/**
*/
protected $name = null;
/**
*/
protected $value = null;
function __construct($name = null, $value = null) {
$this->setName($name);
$this->setValue($value);
}
public function getName() {
return $this->name;
}
public function setName($name) {
$this->name = $name;
}
public function getValue() {
return $this->value;
}
public function setValue($value) {
$this->value = $value;
}
}
?>
<?php
namespace MyCompanyBundle\Model\SolrResults;
use JMS\SerializerBundle\Annotation\AccessType,
JMS\SerializerBundle\Annotation\Accessor,
JMS\SerializerBundle\Annotation\XmlRoot,
JMS\SerializerBundle\Annotation\Type,
JMS\SerializerBundle\Annotation\XmlAttribute,
JMS\SerializerBundle\Annotation\SerializedName,
JMS\SerializerBundle\Annotation\Since,
JMS\SerializerBundle\Annotation\XmlValue,
JMS\SerializerBundle\Annotation\XmlList,
JMS\SerializerBundle\Annotation\Exclude;
/**
*/
class Document {
/**
*/
protected $simpleTypes = array();
function __construct($simpleTypes = null) {
$this->setSimpleTypes($simpleTypes);
}
public function getSimpleTypes() {
return $this->simpleTypes;
}
public function setSimpleTypes($simpleTypes) {
if (!is_array($simpleTypes)) $simpleTypes = array();
$this->simpleTypes = $simpleTypes;
}
}
?>
<?xml version="1.0" encoding="UTF-8"?>
<doc>
<entry name="foo1"><![CDATA[bar]]></entry>
<entry name="foo2">12345</entry>
</doc>
= true, entry= "xxx") where xxx would be nodeName for any elements in my
$simpleTypes array but since I can have different class in this array, I'd
prefer that JMSSerializer can use the XMLRoot value defined in my "Integer"
and "String" classes.
Is there any way to do that or should I have two arrays, one for String
elements and the other for Integer ones ?
Thanks.
Rémi
--
If you want to report a vulnerability issue on symfony, please send it to
security at symfony-project.com
You received this message because you are subscribed to the Google
Groups "Symfony2" group.
To unsubscribe from this group, send email to
For more options, visit this group at
http://groups.google.com/group/symfony2?hl=en
--
If you want to report a vulnerability issue on symfony, please send it to security at symfony-project.com

You received this message because you are subscribed to the Google
Groups "Symfony2" group.
To post to this group, send email to symfony2-/***@public.gmane.org
To unsubscribe from this group, send email to
symfony2+unsubscribe-/***@public.gmane.org
For more options, visit this group at
http://groups.google.com/group/symfony2?hl=en
Loading...