Convert Object To Json In Java

9 min read

Convert object to JSON in Java is a common requirement when building REST APIs, persisting data, or exchanging information between services. JSON (JavaScript Object Notation) has become the de‑facto format for lightweight data interchange because it is human‑readable, language‑agnostic, and easy to parse. In Java, turning a plain object into its JSON representation can be done with several mature libraries, each offering different features, performance characteristics, and configuration options. This guide walks you through the concepts, demonstrates practical code snippets, and highlights best practices so you can choose the right approach for your project That alone is useful..


Why Convert Objects to JSON?

  • Interoperability: JSON is understood by virtually every modern programming language, making it ideal for communication between heterogeneous systems.
  • Web Services: Most RESTful APIs expect request and response payloads in JSON format.
  • Configuration & Storage: Many applications store settings or logs as JSON files because they are easy to edit and version‑control.
  • Debugging & Logging: Serializing objects to JSON provides a clear snapshot of state that can be logged or inspected during troubleshooting.

When you convert object to JSON in Java, you essentially serialize the object's fields into a string that follows JSON syntax ({ "field": value, ... Worth adding: }). The reverse operation—parsing JSON back into an object—is called deserialization, but this article focuses on the serialization side.


Popular Libraries for JSON Conversion

Library Maven Coordinates Key Features Typical Use‑Case
Jackson (com.Plus, jackson. fasterxml.15.On top of that, jackson. Worth adding: json. bind-api</artifactId><version>1.bind</groupId><artifactId>javax.json.On top of that, bind-api + implementation) <dependency><groupId>javax. fasterxml.Even so, google. g.So eclipse</groupId><artifactId>yasson</artifactId><version>3. So json. So code. code.That said, gson:gson) <dependency><groupId>com. Worth adding: 0</version></dependency><br>Implementation e. bind:javax.gson</groupId><artifactId>gson</artifactId><version>2.In real terms, , <dependency><groupId>org. Practically speaking, core:jackson-databind) <dependency><groupId>com. Practically speaking, 2</version></dependency>
Gson (com. json.1</version></dependency> Simple API, good for quick prototyping, supports arbitrary Java objects without annotations Android projects, lightweight utilities
JSON‑Binding (JSON‑B) (`javax.google.Worth adding: 10. Now, core</groupId><artifactId>jackson-databind</artifactId><version>2. 0.

All three libraries can convert object to JSON in Java with just a few lines of code. The sections below show how to use each one Worth keeping that in mind..


Step‑by‑Step Examples

Assume we have a simple POJO representing a user:

public class User {
    private long id;
    private String name;
    private String email;
    private transient String password; // will be ignored by default

    // Constructors, getters, setters omitted for brevity
}

1. Using Jackson

Jackson’s ObjectMapper is the central class for serialization.

import com.fasterxml.jackson.databind.ObjectMapper;

public class JacksonExample {
    public static void main(String[] args) throws Exception {
        User user = new User(1, "Alice Smith", "alice@example.com", "secret");
        ObjectMapper mapper = new ObjectMapper();

        // Pretty‑print with indentation (optional)
        String json = mapper.writerWithDefaultPrettyPrinter()
                            .writeValueAsString(user);

        System.out.println(json);
    }
}

Output

{
  "id" : 1,
  "name" : "Alice Smith",
  "email" : "alice@example.com"
}

Note: The password field is omitted because it is marked transient. You can also control inclusion with @JsonIgnore or @JsonProperty That's the part that actually makes a difference..

2. Using Gson

Gson provides a Gson builder for configuration.

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class GsonExample {
    public static void main(String[] args) {
        User user = new User(2, "Bob Jones", "bob@example.com", "hidden");
        Gson gson = new GsonBuilder()
                .setPrettyPrinting()
                .

        String json = gson.toJson(user);
        System.out.println(json);
    }
}

Output

{
  "id": 2,
  "name": "Bob Jones",
  "email": "bob@example.com"
}

Gson automatically ignores transient fields, just like Jackson Small thing, real impact..

3. Using JSON‑B (Yasson implementation)

JSON‑B requires a Jsonb instance.

import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;

public class JsonbExample {
    public static void main(String[] args) {
        User user = new User(3, "Carol Lee", "carol@example.com", "pwd");
        Jsonb jsonb = JsonbBuilder.create();

        String json = jsonb.toJson(user);
        System.out.println(json);
    }
}

Output (default formatting is compact; you can enable pretty‑print via a custom JsonbConfig)

{"id":3,"name":"Carol Lee","email":"carol@example.com"}

To get pretty‑printed output:

JsonbConfig config = new JsonbConfig().withFormatting(true);
Jsonb jsonb = JsonbBuilder.create(config);

Handling Complex Objects

Real‑world domain models often contain nested objects, collections, enums, or dates. Below are strategies for each scenario.

Nested Objects

public class Order {
    private long orderId;
    private User customer; // nested object
    private List items;
    // getters/setters
}

All three libraries serialize the nested User automatically, producing a JSON object inside the customer field And it works..

Collections & Arrays

Lists, sets, and arrays are converted to JSON arrays. Example with Jackson:

List items = Arrays.asList(
        new Item(101, "Laptop", 999.99),
        new Item(102, "Mouse", 29.99)
);
order.setItems(items);

Resulting JSON snippet:

"items":[
  {"productId":101,"name":"Laptop","price":999.99},
  {"productId":102,"name":"Mouse","price":29.99}
]

Custom Serializers

Sometimes you need to format a field differently (e.g., date as ISO‑8601 string) or exclude it conditionally.

Jackson – annotate with @JsonSerialize or add a module:


```java
public class CustomDateSerializer extends JsonSerializer {
    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME;

    @Override
    public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        gen.writeString(value.format(FORMATTER));
    }
}

// Usage
public class Event {
    private String name;
    @JsonSerialize(using = CustomDateSerializer.class)
    private LocalDateTime timestamp;
    // getters/setters
}

For global configuration, register a module:

ObjectMapper mapper = new ObjectMapper();
JavaTimeModule timeModule = new JavaTimeModule();
timeModule.addSerializer(LocalDateTime.class, new CustomDateSerializer());
mapper.registerModule(timeModule);

Gson – implement JsonSerializer<T> and register it:

public class LocalDateTimeAdapter implements JsonSerializer {
    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME;

    @Override
    public JsonElement serialize(LocalDateTime src, Type typeOfSrc, JsonSerializationContext context) {
        return new JsonPrimitive(src.format(FORMATTER));
    }
}

// Registration
Gson gson = new GsonBuilder()
        .Even so, registerTypeAdapter(LocalDateTime. class, new LocalDateTimeAdapter())
        .setPrettyPrinting()
        .

**JSON‑B** – provide a `JsonbAdapter`:

```java
public class LocalDateTimeAdapter implements JsonbAdapter {
    private static final DateTimeFormatter FMT = DateTimeFormatter.ISO_LOCAL_DATE_TIME;

    @Override
    public String adaptToJson(LocalDateTime obj) throws Exception {
        return obj.format(FMT);
    }

    @Override
    public LocalDateTime adaptFromJson(String obj) throws Exception {
        return LocalDateTime.parse(obj, FMT);
    }
}

// Registration via JsonbConfig
JsonbConfig config = new JsonbConfig()
        .withAdapters(new LocalDateTimeAdapter())
        .withFormatting(true);
Jsonb jsonb = JsonbBuilder.

### Enums

By default, all three libraries serialize enums as their constant names (`"PENDING"`, `"SHIPPED"`). To use a custom representation (e.g.

**Jackson**
```java
public enum Status {
    @JsonProperty("P") PENDING,
    @JsonProperty("S") SHIPPED,
    @JsonProperty("C") CANCELLED
}

Gson

public enum Status {
    @SerializedName("P") PENDING,
    @SerializedName("S") SHIPPED,
    @SerializedName("C") CANCELLED
}

JSON‑B

@JsonbTypeAdapter(StatusAdapter.class)
public enum Status { PENDING, SHIPPED, CANCELLED }

public class StatusAdapter implements JsonbAdapter {
    private static final Map TO_JSON = Map.So naturally, stream()
        . Now, pENDING, "P",
        Status. CANCELLED, "C"
    );
    private static final Map FROM_JSON = TO_JSON.Also, entrySet(). Still, of(
        Status. Which means collect(Collectors. Still, sHIPPED, "S",
        Status. Because of that, toMap(Map. Entry::getValue, Map.

    @Override public String adaptToJson(Status e) { return TO_JSON.get(e); }
    @Override public Status adaptFromJson(String s) { return FROM_JSON.get(s); }
}

Polymorphism

When a field is an interface or abstract class, the serializer must know the concrete type to include type information Most people skip this — try not to..

Jackson – enable default typing or use annotations:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({
    @JsonSubTypes.Type(value = CreditCardPayment.class, name = "credit"),
    @JsonSubTypes.Type(value = PayPalPayment.class, name = "paypal")
})
public interface Payment { }

public class Order {
    private Payment payment; // serialized with "type":"credit"
}

Gson – requires a custom TypeAdapterFactory or the RuntimeTypeAdapterFactory utility (from gson-extras):

RuntimeTypeAdapterFactory factory = RuntimeTypeAdapterFactory
        .of(Payment.class, "type")
        .registerSubtype(CreditCardPayment.class, "credit")
        .registerSubtype(PayPalPayment.class, "paypal");

Gson gson = new GsonBuilder()
        .registerTypeAdapterFactory(factory)
        .create();

JSON‑B – uses @JsonbTypeInfo and @JsonbSubtype:

@JsonbTypeInfo(key = "type")
@JsonbSubtypes({
    @JsonbSubtype(value = CreditCardPayment.class, name = "credit"),
    @JsonbSubtype(value = PayPalPayment.class

### Handling Polymorphic Fields Across Libraries  

While enums are straightforward because they map directly to string codes, polymorphic collections require a bit more care when you want the same shape of data regardless of which framework is used. Below are concise patterns for each technology, followed by a short discussion of integration tips that apply universally.

#### Jackson  

* **Dynamic typing via `@JsonTypeInfo`** – By attaching a type discriminator property (e.g., `"payment_type": "credit"`) the serializer can inspect the value at runtime and select the appropriate subclass adapter. This works even if the concrete class hierarchy changes later, as long as the mapping between the discriminator string and the subtype remains stable.  
* **Custom adapters** – If your domain model already contains rich metadata (e.g., pricing rules, expiration dates) attached to each payment instance, you may embed those details inside the discriminator object rather than relying solely on a simple string. A common pattern is to keep the type identifier separate from payload data, so the outer JSON stays clean while still preserving full context.  

```java
@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = "type")
@JsonSubTypes({
    @JsonSubTypes.Type(value = CreditCardPayment.class, name = "credit"),
    @JsonSubTypes.Type(value = PayPalPayment.class, name = "paypal")
})
public interface Payment { }

// Inside an Order entity
private Payment payment;                     // will be written as {"type":"credit","...}"

Gson

  • RuntimeTypeAdapterFactory – When you register a custom factory for a concrete class, Gson automatically knows how to deserialize objects identified by either ID or name. The factory receives the raw byte stream, extracts the type identifier, creates the correct subclass, and copies the remaining fields. Because the mechanism is built into the library, adding new subtypes does not require extra annotation boilerplate.
  • Handling nested polymorphism – Nested collections (e.g., a list of orders within a shipment) also benefit from this approach. Each element gets its own type tag, allowing deep hierarchies to remain self‑describing.
RuntimeTypeAdapterFactory factory = RuntimeTypeAdapterFactory
        .of(Payment.class, "type")
        .registerSubtype(CreditCardPayment.class, "credit")
        .registerSubtype(PayPalPayment.class, "paypal");

Gson gson = new GsonBuilder()
        .registerTypeAdapterFactory(factory)
        .create();

JSON‑B

  • @JsonbTypeInfo + @JsonbSubtype – Similar to Jackson’s approach, but JSON‑B expects a dedicated meta‑information block per object. The key attribute defines the primary discriminator field (commonly "type"), and each subtype registers a matching entry under value. This gives you explicit control over the location of type hints, which is especially useful when you want the meta‑data to appear after the main payload.
@JsonbTypeInfo(key = "type")
@JsonbSubtypes({
    @JsonbSubtype(value = CreditCardPayment.class, name = "credit"),
    @JsonbSubtype(value = PayPalPayment.class, name = "paypal")
})
public class Order {
    // … other fields …
    @JsonbField(type = JsonbTypeInfo.AsOF_TIME)
    private List lines;
}

Practical Recommendations

  1. Consistency of Discriminator Keys – Choose one string (e.g., "type" or "paymentKind") and stick with it across all library usages. Mixing keys leads to ambiguous deserialization errors and makes debugging harder.
  2. Versioning Considerations – If your API version changes, consider embedding a minor version number alongside the type token (e.g., "type":"credit_v2"). This allows you to evolve the schema without breaking existing clients.
  3. Performance – Polymorphic adaptation incurs a small overhead because the serializer must resolve the correct subclass before invoking the normal serialization path. For high‑throughput services, profile the hot paths (typically bulk import pipelines) and, if needed, pre‑populate the type field during object construction to reduce reflection latency.
  4. Testing – Write unit tests that round‑trip a fully populated polymorphic object through each library independently. Verify that the original type identifier survives the transformation and that all inner fields are preserved unchanged.

Conclusion

All three popular JSON libraries provide reliable mechanisms for representing polymorph

Fresh Stories

Current Topics

Branching Out from Here

See More Like This

Thank you for reading about Convert Object To Json In Java. We hope the information has been useful. Feel free to contact us if you have any questions. See you next time — don't forget to bookmark!
⌂ Back to Home