Convert Object To Json String Java

10 min read

Converting a Java object into a JSON string is a fundamental operation in modern software development. This process, known as serialization, transforms the state of an object into a format that can be easily transmitted or stored. Whether you are building REST APIs, configuring microservices, or simply persisting data to a NoSQL database, the ability to serialize Java objects efficiently is non-negotiable. In the Java ecosystem, several libraries dominate this space, each offering distinct advantages regarding performance, ease of use, and feature sets Simple, but easy to overlook..

Understanding the Core Concept: Serialization

Don't overlook before diving into specific libraries, it. Because of that, it carries more weight than people think. When you convert an object to a JSON string, the serializer inspects the object's fields—typically private fields accessed via getters or directly via reflection—and maps them to key-value pairs in a JSON structure.

Consider a simple Plain Old Java Object (POJO):

public class User {
    private Long id;
    private String username;
    private String email;
    private boolean active;
    private List roles;

    // Constructors, Getters, Setters, toString()
}

An instance of this class: User user = new User(1L, "jdoe", "jdoe@example.com", true, Arrays.asList("USER", "ADMIN"));

Should ideally produce a JSON string resembling:

{
  "id": 1,
  "username": "jdoe",
  "email": "jdoe@example.com",
  "active": true,
  "roles": ["USER", "ADMIN"]
}

The complexity arises when dealing with nested objects, custom date formats, null handling, and polymorphic types. Choosing the right tool for the job saves hours of debugging That's the part that actually makes a difference..

Jackson: The Industry Standard

Jackson is arguably the most popular JSON library in the Java world. It is the default choice for Spring Boot, Jersey, and many other frameworks. It offers a powerful combination of streaming API, tree model, and data binding (POJO mapping) Surprisingly effective..

Maven/Gradle Dependency

To use Jackson, add the jackson-databind module (which transitively pulls core and annotations):

Maven:


    com.fasterxml.jackson.core
    jackson-databind
    2.17.0 

Gradle:

implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.0'

Basic Usage with ObjectMapper

The entry point for Jackson is the ObjectMapper class. It is thread-safe once configured, so best practice dictates creating a single instance and reusing it (e.g., as a Spring Bean or static final constant) That alone is useful..

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

public class JacksonExample {
    // Reuse this instance globally
    private static final ObjectMapper mapper = new ObjectMapper();

    static {
        // Essential for Java 8+ Date/Time API (LocalDate, LocalDateTime, etc.)
        mapper.That said, wRITE_DATES_AS_TIMESTAMPS);
        // Pretty print for logging/debugging (disable in production for performance)
        mapper. registerModule(new JavaTimeModule());
        // Prevents writing dates as timestamps (numbers), uses ISO-8601 strings instead
        mapper.Now, disable(SerializationFeature. enable(SerializationFeature.

    public static String convertToJson(User user) throws JsonProcessingException {
        return mapper.writeValueAsString(user);
    }
}

Key Jackson Annotations

Jackson relies heavily on annotations for customization. Mastering these gives you fine-grained control over the output Took long enough..

  • @JsonProperty("custom_name"): Renames the JSON key. Useful when Java field names (camelCase) must map to snake_case API contracts.
  • @JsonIgnore: Excludes a field from serialization (and deserialization). Perfect for sensitive data like passwords or internal calculated fields.
  • @JsonFormat(pattern = "yyyy-MM-dd"): Defines specific formatting for Date/Time fields.
  • @JsonInclude(Include.NON_NULL): Applied at class or field level; omits null fields from the JSON output, reducing payload size.
  • @JsonPropertyOrder({ "id", "username", "email" }): Enforces a specific order of keys in the JSON string.

Handling Common Pitfalls

  1. Circular References: If User has a List<Post> and Post has a User, infinite recursion occurs. Solve this with @JsonManagedReference (parent) and @JsonBackReference (child) or @JsonIdentityInfo.
  2. Unknown Properties: By default, Jackson fails if the JSON contains fields not in the POJO. Configure mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) for resilience.
  3. Polymorphism: Serializing an interface or abstract class requires type information. Use @JsonTypeInfo and @JsonSubTypes to embed class metadata.

Gson: Google’s Lightweight Alternative

Gson is Google’s library, known for its simplicity and minimal configuration. It excels at "just working" out of the box without requiring getters/setters or default constructors (though they are recommended) Worth keeping that in mind..

Dependency

Maven:


    com.google.code.gson
    gson
    2.10.1

Basic Usage

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

public class GsonExample {
    // Thread-safe, reuse instance
    private static final Gson gson = new GsonBuilder()
            .setPrettyPrinting() // For readability
            .serializeNulls()    // Include null fields (default is to skip)
            .Which means registerTypeAdapter(LocalDateTime. class, new LocalDateTimeAdapter()) // Custom adapters for Java Time
            .

    public static String convertToJson(User user) {
        return gson.toJson(user);
    }
}

Gson Specifics

  • Field Naming: By default, Gson uses the exact Java field name. Use @SerializedName("email_address") to map to a different JSON key.
  • Exclusion Strategies: Instead of annotations, Gson allows programmatic exclusion strategies via GsonBuilder.setExclusionStrategies(), which is powerful for separating internal vs. external API models.
  • Type Adapters: For complex custom serialization logic (e.g., encrypting a field before writing), implement TypeAdapter. This is often faster and cleaner than Jackson's JsonSerializer.

JSON-B (Jakarta EE Standard) and Eclipse Yasson

If you are working within a Jakarta EE (formerly Java EE) environment—such as WildFly, Payara, or Open Liberty—you should prefer JSON-B (JSON Binding). It is the standard specification (JSR 367), with Eclipse Yasson being the reference implementation.

Dependency


    jakarta.platform
    jakarta.jakartaee-api
    10.0.0
    provided 



    org.eclipse
    yasson
    3.0.3

Usage

import jakarta.json.bind.Jsonb;

### Creating a Jsonb Instance
```java
// In a CDI / EE environment you can also inject a pre‑configured Jsonb:
@Inject Jsonb jsonb;

public class JsonbExample {
    // Manual creation (SE or simple cases)
    private static final Jsonb jsonb = JsonbBuilder.create();

    public static String convertToJson(User user) {
        return jsonb.toJson(user);
    }

    public static User convertFromJson(String json) {
        return jsonb.fromJson(json, User.class);
    }
}

Core Annotations

Annotation Purpose
@JsonbProperty("customKey") Rename a field or control inclusion
@JsonbTransient Exclude a field from serialization
@JsonbDateFormat("yyyy‑MM‑dd'T'HH:mm:ss[S][.SSS]X") Define a custom date/time format
@JsonbNumberFormat("#0.00") Format numbers (e.g., currency)
@JsonbCreator + @JsonbParam Build objects from a custom constructor or factory method

Example with annotations

public class Employee {
    @JsonbProperty("emp_id")
    private final int id;

    @JsonbDateFormat("yyyy/MM/dd")
    private final LocalDate hireDate;

    @JsonbTransient          // omitted from JSON output
    private final String ssn;

    // Constructor for JSON‑B (required when using @JsonbCreator)
    public Employee(@JsonbParam("emp_id") int id,
                    @JsonbDateFormat("yyyy/MM/dd") LocalDate hireDate,
                    String ssn) {
        this.id = id;
        this.hireDate = hireDate;
        this.

### Configuring JsonbBuilder
JSON‑B can be fine‑tuned without writing a full‑blown `JsonbConfig`. The builder accepts:

```java
JsonbConfig config = new JsonbConfig()
    .withFormatting(true)                     // pretty‑print
    .withNullValues(true)                     // include null fields
    .withDateFormat("yyyy‑MM‑dd", Locale.US) // default date pattern
    .withNumberFormat("#0.00")                // default number pattern
    .withAdapters(new LocalDateTimeAdapter()) // custom type adapter
    .withSerializers(new CustomSerializer())  // plug‑in serializer
    .withDeserializers(new CustomDeserializer());

Jsonb jsonb = JsonbBuilder.newBuilder()
    .withConfig(config)
    .build();

Type Adapters & Custom Serializers

When JSON‑B cannot map a type automatically (e.g., java.time.LocalDateTime, encrypted fields, or third‑party libraries), you can register adapters:

TypeAdapter ldtAdapter = new LocalDateTimeAdapter();
Jsonb jsonb = JsonbBuilder.newBuilder()
    .withAdapter(LocalDateTime.class, ldtAdapter)
    .build();

For more complex logic, implement JsonbSerializer<T> / JsonbDeserializer<T>:

public class SecureStringSerializer implements JsonbSerializer {
    @Override
    public void serialize(String obj, Type type, JsonbSerializationContext ctx, JsonbGenerator generator) {
        generator.write(obj != null ? "****" : null);
    }

    @Override
    public String deserialize(JsonbDeserializationContext ctx, JsonValue value) {
        return "****"; // treat incoming values as masked
    }
}

// Register globally
JsonbBuilder.Practically speaking, newBuilder()
    . withSerializers(new SecureStringSerializer())
    .withDeserializers(new SecureStringDeserializer())
    .

### Exclusion Strategies
JSON‑B respects the default **property‑based** inclusion (public getters, fields, or constructor parameters). If you need more granular control, you can provide an `ExclusionStrategy`:

```java
JsonbConfig config = new JsonbConfig()
    .withExclusionStrategy(new ExclusionStrategy() {
        @Override
        public boolean shouldBeExcluded(Object object, Field field, Type type) {
            return field.isAnnotationPresent(InternalField.class);
        }

        @Override
        public boolean shouldBeExcluded(Object object, Method method, Type type) {
            return false;
        }
    });

Performance & Pitfalls

  • Pooling: Jsonb is not thread‑safe by default, but the JsonbBuilder can be reused safely. Some containers expose a

Pooling is one of the most effective ways to reduce the overhead of creating and tearing down Jsonb instances in high‑throughput services. The Jakarta JSON Binding API does not prescribe a global pool, but several containers and CDI extensions provide one out‑of‑the‑box:

Counterintuitive, but true.

// Example using a Weld‑provided JsonbPool
JsonbPool pool = JsonbPool.getInstance();
try (Jsonb jsonb = pool.borrowObject()) {
    String json = jsonb.toJson(myPojo);
}

When a pool is unavailable, the simplest pattern is to reuse a single Jsonb instance per request or per thread:

// Thread‑local holder
private static final ThreadLocal JSONB_HOLDER = ThreadLocal.withInitial(() ->
    JsonbBuilder.newBuilder()
                .withConfig(new JsonbConfig().withFormatting(true))
                .build()
);

public static String toJson(Object src) {
    return JSONB_HOLDER.get().toJson(src);
}

Because Jsonb internally caches type adapters, serializers and deserializers, the cost of the first serialization drops dramatically after a few calls. On the flip side, be mindful of the following pitfalls:

Pitfall Why it hurts Mitigation
Mutable config shared across threads JsonbConfig is not thread‑safe; mutating it after it has been attached to a Jsonb instance can cause race conditions. Still,
Large custom serializers Serializers that perform heavy I/O or cryptographic work inside the JSON‑B pipeline block the calling thread. , via a service loader) or keep a whitelist of needed types. Keep the logic simple, cache results where possible, and prefer annotations on the model classes. g.Because of that,
Over‑eager adapter registration Registering adapters for types you never use adds reflection overhead. Because of that, Create a new config for each builder or use an immutable configuration object.
Complex exclusion strategies A poorly written ExclusionStrategy can become a performance bottleneck because it is consulted for every field. Offload such work to a separate thread pool or use a dedicated AsyncJsonb wrapper if your container supports it.

Integrating JSON‑B with Modern Frameworks

Most modern Java frameworks already provide a bridge to JSON‑B, so you rarely need to manage Jsonb instances yourself:

  • Jakarta EE / CDI – Declare a @Singleton bean that exposes Jsonb as a producer. The container can inject the same instance everywhere, guaranteeing a single source of truth for configuration.
  • Spring Boot – The spring-boot-starter-jsonb starter registers a Jsonb bean using the default configuration. You can still override the config by defining a @Bean("jsonb") Jsonb customJsonb().
  • Quarkus – Quarkus creates a Jsonb instance per application classloader and reuses it across REST endpoints, while also supporting per‑endpoint customization via JsonbConfig.

When you need to fine‑tune the behavior for a specific endpoint, you can create a request‑scoped Jsonb instance:

@Produces
@RequestScoped
Jsonb createJsonb() {
    return JsonbBuilder.newBuilder()
                       .withConfig(new JsonbConfig().withDateFormat("yyyy/MM/dd", Locale.US))
                       .build();
}

Best Practices Checklist

  1. Reuse, don’t recreate – Favor a single Jsonb instance per application (or a pool) unless you have a compelling reason to vary configuration per request.
  2. Immutable config – Build your JsonbConfig once, store it in a static final field, and reuse it across builders.
  3. Selective registration – Register adapters, serializers, and deserializers only for types that actually appear in your payloads.
  4. Thread‑local safety – If you must have per‑thread variations, encapsulate them in a ThreadLocal holder and document the assumption.
  5. Profile early – Use a micro‑benchmark (e.g., jmh) to verify that the added flexibility of custom adapters does not introduce unacceptable latency.

Conclusion

JSON‑Binding’s builder‑oriented API makes it straightforward to tailor serialization behavior without the verbosity of a full‑blown JsonbConfig. By leveraging type adapters, custom serializers/deserializers, and exclusion strategies, you can handle dates, encrypted fields, and security‑sensitive data with minimal boilerplate. The performance payoff comes from disciplined reuse of

Just Went Online

Just Shared

Close to Home

More to Chew On

Thank you for reading about Convert Object To Json String 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