Java Engine
This engine relies on the Jackson library for JSON serialization. We also implement the java Optional type to make the work with nullable objects a bit safer.
Getting Started
Set a package
Once you add a Java engine, you should navigate to the engine config and set a package for the Java models.
Required Dependencies
There are a few extra Jackson dependencies, namely because:
- jackson-annotations: For annotations, such as @JsonIgnore
- jackson-datatype-jsr310: To manage Date & DateTime
- jackson-datatype-jdk8: To manage the Optional type
See the maven dependencies listed below. At the time of writing this article, the last Jackson version was 2.13.2, make sure to update it if outdated.
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.2.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.13.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.13.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.13.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
<version>2.13.2</version>
</dependency>
</dependencies>
Register Modules
Once you got all the required dependencies, you need to register the Jackson modules in your Java project before using the JSON serialization. You can see example below, registering modules in the main function.
import com.fasterxml.jackson.databind.ObjectMapper;
import model.User;
public class Main {
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.findAndRegisterModules();
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
// assume we generated a simple User model that we're going to parse from JSON
String json = "{\"username\" : \"john_doe12\", \"created\": \"2020-03-09T22:18:26.625Z\"}";
User user = mapper.readerFor(User.class).readValue(json);
System.out.println(user.getUsername()); // prints out 'john_doe12'
}
}
Data Types
Standard
Since java doesn't support unsigned data types, all unsigned data types are expressed as signed data types.
Design | Java | When Optional |
---|---|---|
bool | boolean | Boolean |
int | int | Integer |
int8 | byte | Byte |
int16 | short | Short |
int32 | int | Integer |
int64 | long | Long |
uint | int | Integer |
uint8 | byte | Byte |
uint16 | short | Short |
uint32 | int | Integer |
uint64 | long | Long |
float | float | Float |
double | double | Double |
string | String | String |
char | char | Character |
byte | byte | Byte |
bytea | byte[] | byte[] |
date | LocalDate | LocalDate |
datetime | LocalDateTime | LocalDateTime |
Complex
Name | Java Type |
---|---|
Array | Array |
Map | HashMap |
Config
Among other things, you can configure access modifiers in 3 different categories:
- Entity for class/enum, i.e. public class User
- Field for class properties
- Inner for class methods including getters/setters
Optionals
Introduced in Java 8, Optionals bring a certain layer of safety when working with nullable types. We use optionals as a return type of methods and getters of properties marked optional in design.
Java Optionals were designed mainly as a return type, thus we never use it to wrap class properties.
Date & DateTime
We at OneGen generally prefer to serialize date/time values into ISO 8601 as it's both readable and universally accepted. Our Java Engine implementation is no exception. It's very easy to configure with Jackson.
ObjectMapper mapper = new ObjectMapper();
mapper.findAndRegisterModules();
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
Example
Let's take a look at a pre-generated User model and how to work with it.
model/User.java
package model; // you can define your model package in config
import com.fasterxml.jackson.annotation.JsonIgnore;
import java.util.Optional;
import java.time.LocalDate;
public class User {
private int id;
private String email;
@JsonIgnore
private String password; // password is marked "Skip Parsing" in design
private String firstName;
private String lastName; // notice the optional getter below
private LocalDate birthday;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public Optional<String> getLastName() { // optional getter
return Optional.ofNullable(lastName);
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public LocalDate getBirthday() {
return birthday;
}
public void setBirthday(LocalDate birthday) {
this.birthday = birthday;
}
}
Main.java
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import java.io.IOException;
import java.time.LocalDate;
import model.User;
public class Main {
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.findAndRegisterModules();
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
// Serialize to JSON
User john = new User();
john.setEmail("john@doe.com");
john.setFirstName("JohnnyLawrence");
john.setBirthday(LocalDate.now());
String johnSerialized = mapper.writeValueAsString(john);
System.out.println(johnSerialized);
// Deserialize from JSON
String json = "{\"id\":234,\"firstName\":\"Jackson\",\"email\":\"digitalninja@mydomain.com\"}";
User jackson = mapper.readerFor(User.class).readValue(json);
System.out.println(jackson.getFirstName()); // prints out "Jackson"
}
}