robtimus / json-object-mapper
A library to map objects to and from JSON
Installs: 17
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 2
Forks: 2
Open Issues: 0
pkg:composer/robtimus/json-object-mapper
Requires
- php: >=5.3.2
- doctrine/annotations: >=1.2.7
- doctrine/cache: >=1.5.4
Requires (Dev)
- phpunit/phpunit: ~4
This package is auto-updated.
Last update: 2022-08-03 19:41:28 UTC
README
Converts objects to and from JSON (serialization and deserialization respectively). Although built upon json_encode and json_decode, it supports any type of object, not just stdClass.
Basic usage
An ObjectMapper instance has two methods:
toJSONtakes an object or array and serializes it to a JSON string.fromJSONtakes a JSON string and deserializes it to an object or array of objects. The type of object must be given, either as its fully qualified name, or as an ReflectionClass instance).
Example:
$mapper = new ObjectMapper();
$json = $mapper->toJSON($object);
$object = $mapper->fromJSON($json, '\MyClass');
JSON Property mapping
By default, all public properties, getters (both get and is prefixes are supported) and setters are included. These need to specify their types using phpDocumenter annotations. For instance:
class Person {
/**
* @var string
*/
public $firstName;
private $lastName;
/**
* @return string
*/
public function getLastName() {
return $this->lastName;
}
/**
* @param string $value
*/
public function setLastName($value) {
$this->lastName = $value;
}
}
The following are supported:
- Scalar types (
boolean,bool,integer,int,float,double,string). - Object types.
\stdClass.- Arrays of the above; append
[]after the type.
Including and excluding JSON properties
Note: all of the below annotations are located in namespace Robtimus\JSON\Mapper\Annotations, and either need to be included with a use statement, or be used with their fully qualified class names.
@JSONAccessorType
A class can be annotated with @JSONAccessorType("<ACCESSOR_TYPE>") to change what is automatically included. The following are valid accessor types:
METHOD: all getters and setters are included, even if they are not public.PROPERTY: all properties are included, even if they are not public.PUBLIC_MEMBER: all public properties, getters and setters are included.NONE: no properties, getters or setters are included unless explicitly included. Use this if you want to explicitly include JSON properties.
@JSONProperty
A single property, getter or setter can be explicitly included by annotating it with @JSONProperty, even if it would otherwise be excluded. This annotation can take an optional name property to override the default property name: @JSONProperty(name = "name").
If no explicit JSON property name is given it is determined as follows:
- For properties, the property name.
- For getters and setters, the getter/setter name with the leading
get,isorsetprefix and any underscores following it immediately removed, then the first character lowercased. If the method name after the prefix is all uppercase it will be considered an acronym and be completely lowercased (e.g.getURL=>url).
@JSONIgnore
A single property, getter or setter can be ignored by annotating it with @JSONIgnore, even if it would otherwise be included (this overrides @JSONProperty).
@JSONReadOnly
A single property can be made read-only (i.e. it will be ignored during deserialization) by annotating it with @JSONReadOnly. The same can also be achieved by making the property private and only providing a getter, or by annotating the setter with @JSONIgnore.
@JSONWriteOnly
A single property can be made write-only (i.e. it will be ignored during serialization) by annotating it with @JSONWriteOnly. The same can also be achieved by making the property private and only providing a setter, or by annotating the getter with @JSONIgnore.
@JSONAnyGetter
A single method that takes no arguments and returns an associative array, stdClass instance or an iterator can be annotated with @JSONAnyGetter. The keys and values of the return value will be added to the JSON string during serialization.
Ignoring null values and/or empty arrays
Set the omitNullValues property of an ObjectMapper instance to true to omit JSON properties with null values.
Set the omitEmptyArrays property of an ObjectMapper instance to true to omit JSON properties with empty array values.
JSON Property order
By default, JSON properties will have an undetermined order during serialization. A class can be annotated with @JSONPropertyOrder to create a specific order. This annotation can be used in two ways:
@JSONPropertyOrder(alphabetical = true)to use alphabetical ordering.@JSONPropertyOrder(properties = {"property1", "property2", ...})to specify the desired order. Note that this list must include all JSON properties, including inherited JSON properties.
Note that this property order does not include properties returned by methods annotated with @JSONAnyGetter.
Handling unknown properties
By default, when deserializing a JSON string to an object, any JSON property that is not defined in the object will cause a JSONParseException to be thrown. This can be be prevented in one of two ways:
- Set the
allowUndefinedPropertiesproperty of theObjectMapperinstance to true. This will cause any undefined JSON property to be ignored. - Provide a single method that takes two arguments (for the JSON property name and its value), and annotate it with
@JSONAnySetter. This method will be called for each unknown JSON property and its value.
Custom serialization and deserialization
By default, scalar values are used as-is, and object are processed as described above. This behaviour can be changed by providing a custom serializer or deserializer.
Custom serialization
A custom serializer can be created by implementing JSONSerializer, and can be defined for a JSON property in two ways:
-
Annotate a property or getter with
@JSONSerialize(using = "<JSONSerializer class name>")to use a custom serializer for a single property or getter. -
Call
setDefaultSerializeron theObjectMapperinstance to use a custom serializer for all JSON properties of a specific type. For example, to use aDateTimeJSONSerializerwith for allDateTimeJSON properties:$mapper->setDefaultSerializer('\DateTime', new DateTimeJSONSerializer(DateTime::RFC3339_EXTENDED));
Custom serialization
A custom deserializer can be created by implementing JSONDeserializer, and can be defined for a JSON property in two ways:
-
Annotate a property or setter with
@JSONDeserialize(using = "<JSONDeserializer class name>")to use a custom deserializer for a single property or setter. -
Call
setDefaultDeserializeron theObjectMapperinstance to use a custom deserializer for all JSON properties of a specific type. For example, to use aDateTimeJSONDeserializerwith for allDateTimeJSON properties:$mapper->setDefaultDeserializer('\DateTime', new DateTimeJSONDeserializer(DateTime::RFC3339_EXTENDED));
Programmatic mapping
Besides using annotations, mappings for a class can also be created programmatically by creating a ClassDescriptor and adding properties. It can then be added to an ObjectMapper instance using its registerClass method.
The following is a mapping of annotations to the methods that replace them:
@JSONAccessorType: no replacement, as programmatic mapping replaces all automatic inclusion of JSON properties.@JSONProperty: calladdPropertyorensurePropertyon aClassDescriptorinstance, these returns the added property as an instance ofPropertyDescriptor. The name and type are required; the type can be relative to an optional third argument of typeReflectionClass.@JSONIgnore: no replacement, as programmatic mapping only properties to include can be added.@JSONReadOnly: do not callwithSetteron an added property.@JSONWriteOnly: do not callwithGetteron an added property.@JSONAnyGetter: callwithAnyGetteron aClassDescriptorinstance. This method is additive, so it's possible to specify multiple methods.@JSONAnySetter: callwithAnySetteron aClassDescriptorinstance.@JSONPropertyOrder: callorderPropertieson aClassDescriptorinstance. Provide an array with the JSON properties to order on, or provide no arguments to use alphatical ordering.@JSONSerialize: callwithSerializeron an added property.@JSONDeserialize: callwithDeserializeron an added property.
Note that all getters and setters are callables. This removes the requirement to use instance methods.
An example:
$classDescriptor = new ClassDescriptor(new ReflectionClass('\Person'));
$classDescriptor->addProperty('firstName', 'string')
->withGetter(array(new ReflectionProperty('\Person', 'firstName'), 'getValue'))
->withSetter(array(new ReflectionProperty('\Person', 'firstName'), 'setValue'));
$classDescriptor->addProperty('lastName', 'string')
->withGetter(array(new ReflectionMethod('\Person', 'getLastName'), 'invoke'))
->withSetter(array(new ReflectionMethod('\Person', 'setLastName'), 'invoke'));
$mapper->registerClass($classDescriptor);
Formatting
Similar to json_encode, the toJSON method of an ObjectMapper instance can take a bitmask of options. The same options are supported.