Qson
QSON is an object to JSON mapper
Install / Use
/learn @quarkusio/QsonREADME
QSON json mapper
QSON is an object to json mapper. It does bytecode generation of deserializer (parser) and serializer (writer) classes using Gizmo. QSON was born when it's author (Bill Burke) noticed that Jackson took up a decent portion of boot time for a simple Resteasy JAX-RS Quarkus application. While Jackson is a more mature json mapper and a de facto standard, QSON aims for better integration with Quarkus and Graal. The primary goals of QSON are speed, both boot and runtime, limited heap allocations, a small set of classes (metaspace size), low memory footprint, and zero reflection at runtime.
Limitations
- must use public getter and setter methods that are prefixed with
get,is, orset, or that are annotated with @QsonProperty - only public classes
- Does not support polymorphism
- Only UTF-8 encoding supported
- No array support yet
- Lacks other features something like Jackson may have. Will be adding those features that do not degrade performance and memory footprint
- Qson works best right now with Quarkus. We don't have maven/gradle plugin integration yet to compile bytecode at buildtime in these non-Quarkus environments
Basics
Classes that you want to map to JSON must have a public getter method for each property you want to be able to serialize to JSON
and a public setter method for those properties you want to be able to deserialize from JSON.
If your getter and setter methods are not prefixed with get, is, or set, then you must
mark it as a property using the @QsonProperty annotation.
Every setter or getter method will
be assumed to be something you want to map to JSON unless you use the @io.quarkus.qson.QsonIgnore annotation on the setter or
getter method, or the field of the property. The json property name will be the same name as the Java property one. You can use
the @io.quarkus.qson.QsonProperty annotation to change the json property name mapping.
Here's a simple example:
{
"name": "Cam Newton",
"home-address": "Foxboro"
}
public class Person {
private String name;
private String homeAddress;
private String phone;
@QsonProperty("zip-code")
private String zip;
public String getName() {
return name;
}
public void setName(String n) {
this.name = n;
}
@QsonProperty("phone-number")
public String getPhone() {
return phone;
}
public void setPhone(String p) {
this.phone = p;
}
public String getZip() {
return zip;
}
public void setZip(String z) {
this.zip = z;
}
@QsonProperty
public String homeAddress() {
return homeAddress;
}
@QsonProperty
public Person homeAddress(String a) {
this.homeAddress = a;
}
}
Unmapped json
When parsing, Qson automatically ignores any extra json that does not map to your class.
Qson also supports arbitrary JSON with the io.quarkus.qson.QsonAny annotation. For deserialization, this annotation
must be placed on a method that takes two parameters, a String key, and an Object value. For serialization,
it must be placed on a method that takes no parameters and returns a Map<String, Object>.
public class Pojo {
private Map<String, Object> any;
@QsonAny
public Map<String, Object> getAny() {
return any;
}
@QsonAny
public void setAny(String key, Object val) {
if (this.any == null) this.any = new HashMap<>();
this.any.put(key, val);
}
}
Date Time support
Qson has out-of-the-box support for java.util.Date and java.time.OffsetDateTime. The default
global setting is ISO 8601 Offset Date Time. You can change this by invoking the QsonMapper.dateFormat() method
{
QsonMapper mapper = new QsonMapper();
mapper.dateFormat(QsonDate.Format.MILLISECONDS);
}
The default formats supported are milliseconds, seconds, ISO 8601 OFfset Date Time, and RFC 1123 Date Time. You can
also configure date formatting on a per-property bases using the @io.quarkus.qson.QsonDate annotation. For example
public class MyDates {
private Date patterned;
private OffsetDateTime date;
private List<Date> dates;
@QsonDate(format = QsonDate.Format.SECONDS)
public OffsetDateTime getDate() {
return date;
}
public void setDate(OffsetDateTime date) {
this.date = date;
}
@QsonDate(format = QsonDate.Format.MILLISECONDS)
public List<Date> getDates() {
return dates;
}
public void setDates(List<Date> dates) {
this.dates = dates;
}
@QsonDate(pattern = "yyyy MM dd")
public Date getPatterned() {
return patterned;
}
public void setPatterned(Date patterned) {
this.patterned = patterned;
}
}
Qson Value mappings
Qson supports mapping json literal values directly to a class. For example, if you want to map a number
value to a specific class. You use the @io.quarkus.qson.QsonValue annotation as follows:
public class MyConstructorStringValue {
private String string;
@QsonValue
public MyConstructorStringValue(String str) {
this.string = str;
}
@QsonValue
public String value() {
return string;
}
}
In the above example if you have this json: "hello", the string value will be passed
to the constructor MyConstructorStringValue. For writes, instances of MyConstructorStringValue
will be written as a json string using the value returned from the MyConstructorStringValue.value() method.
You can also place @QsonValue on a setter method instead of on a constructor. For example:
public class MyMethodIntValue {
private int val;
@QsonValue
public void value(int val) {
this.val = val;
}
@QsonValue
public int value() {
return val;
}
}
Programmatic Custom Mappings
Qson has an API, io.quarkus.qson.generator.QsonGenerator, that you can
programmatically use to specify, modify, or augment qson class mappings. QsonMapper
implements this interface. You can override or create a completely new mapping. This
is especially useful for thirdparty libraries where you are not able to annotate the class
you want to map to json.
The QsonGenerator.mappingFor(Class) method will scan the class you pass as a parameter
for qson annotations and return you a io.quarkus.qson.generator.ClassMapping instance
from which you can modify this mapping. The QsonGenerator.overrideMappingFor(Class) does not
scan for annotations and just gives you a ClassMapping instance from which you can specify
the whole mapping for your class.
Custom Parsers with @QsonTransformer
Sometimes you have a thirdparty library that has one or more classess you want to map to
json. The @io.quarkus.qson.QsonTransformer annotation provides you an easier way to define
a mapping for these un-annotatable classes. You can define a transformer class that has
all the annotations you want and mark a method on that transformer class that allocates an
instance of that thirdparty class.
public class Thirdparty {
int val;
public Thirdparty(int val) {
this.val = val;
}
public int val() {
return val;
}
}
public class Transformer {
int x;
@QsonTransformer
public Thirdparty createThirdparty() {
return new Thirdparty(x);
}
@QsonProperty("x")
public void setX(int x) {
this.x = x;
}
}
@Test
public void testTransformer() throws Exception {
String json = "{ \"x\": 42 }";
QsonMapper mapper = new QsonMapper();
mapper.overrideMappingFor(Thirdparty.class).transformer(Transformer.class);
Thirdparty t = mapper.read(json, Thirdparty.class);
Assertions.assertEquals(42, t.getX());
}
This is especially useful for cases where your third party class can only be allocated with a constructor with one or more parameters. The example above shows this.
Custom Writers
You can register custom writers that will produce the json you want for a
specific class by implementing the io.quarkus.qson.writer.QsonObjectWriter interface.
public class Thirdparty {
int val;
public Thirdparty(int val) {
this.val = val;
}
public int val() {
return val;
}
}
public class Custom implements QsonObjectWriter {
@Override
public void write(JsonWriter writer, Object target) {
Thirdparty t = (Thirdparty)target;
String json = "{ \"foobar\": " + target.val() + " }";
writer.writeBytes(json.getBytes());
}
}
@Test
public void testCustomWriter() throws Exception {
QsonMapper mapper = new QsonMapper();
mapper.mappingFor(Thirdparty.class).customWriter(Custom.class);
String json = mapper.writeString(new Thirdparty(12));
Assertions.assertEquals("{ \"foobar\": 12 }", json);
}
Integration Outside of Quarkus
You must first pull in the QSON generator dependency
<dependency>
<groupId>io.quarkus.qson</groupId>
<artifactId>qson-generator</artifactId>
</dependency>
You can read and write json with the io.quarkus.qson.QsonMapper class. Unfortunately, this class does not work with
Graal as it generates bytecode and loads generated parsers and writers at runtime using a custom classloader. Quarkus
has better integration if you have custom settings for Qson (more on that later).
// reading
QsonMapper mapper = new QsonMapper();
InputStream is = ...;
Person p = mapper.read(is, Person.class);
byte[] bytes = ...;
Person p = mapper.read(bytes, Person.class);
String json = "{...}";
Person p = mapper.read(json, Person.clas
Related Skills
node-connect
339.3kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
83.9kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
339.3kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
83.9kCommit, push, and open a PR
