eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – LJB – NPI EA (cat = Core Java)
announcement - icon

Code your way through and build up a solid, practical foundation of Java:

>> Learn Java Basics

Partner – LambdaTest – NPI EA (cat= Testing)
announcement - icon

Distributed systems often come with complex challenges such as service-to-service communication, state management, asynchronous messaging, security, and more.

Dapr (Distributed Application Runtime) provides a set of APIs and building blocks to address these challenges, abstracting away infrastructure so we can focus on business logic.

In this tutorial, we'll focus on Dapr's pub/sub API for message brokering. Using its Spring Boot integration, we'll simplify the creation of a loosely coupled, portable, and easily testable pub/sub messaging system:

>> Flexible Pub/Sub Messaging With Spring Boot and Dapr

1. Introduction

GraphQL is a powerful query language for APIs and provides a flexible and efficient way to interact with our data. When dealing with mutations, it’s typical to perform updates or additions to data on the server. However, in some scenarios, we might need to mutate without returning any data.

In GraphQL, the default behavior is to enforce non-nullability for fields in the schema, meaning that a field must always return a value and cannot be null unless explicitly marked as nullable. While this strictness contributes to the clarity and predictability of the API, there are instances where returning null might be necessary. However, it’s generally considered a best practice to avoid returning null values.

In this article, we’ll explore techniques for implementing GraphQL mutations without retrieving or returning specific information.

2. Prerequisites

For our example, we’ll need the following dependencies:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-graphql</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

The Spring Boot GraphQL Starter provides an excellent solution for quickly setting up a GraphQL server. By leveraging auto-configuration and adopting an annotation-based programming approach, we only need to focus on writing the essential code for our service.

We’ve included the web starter in our config because GraphQL is transport-agnostic. This utilizes Spring MVC to expose the GraphQL API over HTTP. We can access this via the default /graphql endpoint. We can also use other starters, like Spring Webflux, for different underlying implementations.

3. Using Nullable Type

Unlike some programming languages, GraphQL mandates an explicit declaration of nullability for each field in the schema. This approach enhances clarity, allowing us to convey when a field may lack value.

3.1. Writing the Schema

The Spring Boot GraphQL starter automatically locates GraphQL Schema files under the src/main/resources/graphql/** location. It builds the correct structure based on them, and wires special beans to this structure.

We’ll start by creating the schema.graphqls file, and defining the schema for our example:

type Post {
    id: ID
    title: String
    text: String
    category: String
    author: String
}

type Mutation {
    createPostReturnNullableType(title: String!, text: String!, category: String!, authorId: String!) : Int
}

We’ll have a Post entity and a mutation to create a new post. Also, for our schema to pass validation, it must have a query. So, we’ll implement a dummy query that returns a list of posts:

type Query {
    recentPosts(count: Int, offset: Int): [Post]!
}

3.2. Using Beans to Represent Types

In the GraphQL server, every complex type is associated with a Java bean. These associations are established based on the object and property names. That being said, we’ll create a POJO class for our posts:

public class Post {
    private String id;
    private String title;
    private String text;
    private String category;
    private String author;

    // getters, setters, constructor
}

Unmapped fields or methods on the Java bean are overlooked within the GraphQL schema, posing no issues.

3.3. Creating the Mutation Resolver

We must mark the handler functions with the @MutationMapping tag. These methods should be placed within regular @Controller components in our application, registering the classes as data-modifying components in our GraphQL application:

@Controller
public class PostController {

    List<Post> posts = new ArrayList<>();

    @MutationMapping
    public Integer createPost(@Argument String title, @Argument String text, @Argument String category, @Argument String author) {
        Post post = new Post();
        post.setId(UUID.randomUUID().toString());
        post.setTitle(title);
        post.setText(text);
        post.setCategory(category);
        post.setAuthor(author);
        posts.add(post);
        return null;
    }
}

We must annotate the parameters of the method with @Argument according to the properties from the schema. When declaring the schema, we determined that our mutation would return an Int type, without the exclamation mark. This allowed the return value to be null.

4. Creating Custom Scalar

In GraphQL, scalars are the atomic data types that represent the leaf nodes in a GraphQL query or schema.

4.1. Scalars and Extended Scalars

According to the GraphQL specification, all implementations must include the following scalar types: String, Boolean, Int, Float, or ID. Besides that, graphql-java-extended-scalars adds more custom-made scalars like Long, BigDecimal, or LocalDate. However, neither the original nor the extended set of scalars have a special one for the null value. So, we’ll build our scalar in this section.

4.2. Creating the Custom Scalar

To create a custom scalar, we should initialize a GraphQLScalarType singleton instance. We’ll utilize the Builder design pattern to create our scalar:

public class GraphQLVoidScalar {

    public static final GraphQLScalarType Void = GraphQLScalarType.newScalar()
      .name("Void")
      .description("A custom scalar that represents the null value")
      .coercing(new Coercing() {
          @Override
          public Object serialize(Object dataFetcherResult) {
              return null;
          }

          @Override
          public Object parseValue(Object input) {
              return null;
          }

          @Override
          public Object parseLiteral(Object input) {
              return null;
          }
      })
      .build();
}

The key components of the scalar are name, description, and coercing. Although the name and description are self-explanatory, the hard part of creating a custom scalar is graphql.schema.Coercing implementation. This class is responsible for three functions:

  • parseValue(): accepts a variable input object and transforms it into the corresponding Java runtime representation
  • parseLiteral(): receives an AST literal graphql.language.Value as input and transform it into the Java runtime representation
  • serialize(): accepts a Java object and converts it into the output shape for that scalar

Although the implementation of coercing can be quite complicated for a complex object, in our case, we’ll return null for each method.

4.3. Register the Custom Scalar

We’ll start by creating a configuration class where we register our scalar:

@Configuration
public class GraphQlConfig {
    @Bean
    public RuntimeWiringConfigurer runtimeWiringConfigurer() {
        return wiringBuilder -> wiringBuilder.scalar(GraphQLVoidScalar.Void);
    }	
}

We create a RuntimeWiringConfigurer bean where we configure the runtime wiring for our GraphQL schema. In this bean, we use the scalar() method provided by the RuntimeWiring class to register our custom type.

4.4. Integrate the Custom Scalar

The final step is to integrate the custom scalar into our GraphQL schema by referencing it using the defined name. In this case, we use the scalar in the schema by simply declaring scalar Void.

This step ensures that the GraphQL engine recognizes and utilizes our custom scalar throughout the schema. Now, we can integrate the scalar into our mutation:

scalar Void

type Mutation {
    createPostReturnCustomScalar(title: String!, text: String!, category: String!, authorId: String!) : Void
}

Also, we’ll update the mapped method signature to return our scalar:

public Void createPostReturnCustomScalar(@Argument String title, @Argument String text, @Argument String category, @Argument String author)

5. Conclusion

In this article, we explored implementing GraphQL mutations without returning specific data. We demonstrated setting up a server quickly with the Spring Boot GraphQL Starter. Furthermore, we introduced a custom Void scalar to handle null values, showcasing how to extend GraphQL’s capabilities.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

eBook Jackson – NPI EA – 3 (cat = Jackson)