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.

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

Regression testing is an important step in the release process, to ensure that new code doesn't break the existing functionality. As the codebase evolves, we want to run these tests frequently to help catch any issues early on.

The best way to ensure these tests run frequently on an automated basis is, of course, to include them in the CI/CD pipeline. This way, the regression tests will execute automatically whenever we commit code to the repository.

In this tutorial, we'll see how to create regression tests using Selenium, and then include them in our pipeline using GitHub Actions:, to be run on the LambdaTest cloud grid:

>> How to Run Selenium Regression Tests With GitHub Actions

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

1. Introduction

This tutorial is a follow-up to our OData Protocol Guide, where we’ve explored the basics of the OData protocol.

Now, we’ll see how to implement a simple OData service using the Apache Olingo library.

This library provides a framework to expose data using the OData protocol, thus allowing easy, standards-based access to information that would otherwise be locked away in internal databases.

2. What Is Olingo?

Olingo is one of the “featured” OData implementations available for the Java environment – the other being the SDL OData Framework. It is maintained by the Apache Foundation and is comprised of three main modules:

  • Java V2 – client and server libraries supporting OData V2
  • Java V4 – server libraries supporting OData V4
  • Javascript V4 – Javascript, client-only library supporting OData V4

In this article, we’ll cover only the server-side V2 Java libraries, which support direct integration with JPA. The resulting service supports CRUD operations and other OData protocol features, including ordering, paging and filtering.

Olingo V4, on the other hand, only handles the lower-level aspects of the protocol, such as content-type negotiation and URL parsing. This means that it’ll be up to us, developers, to code all nitty-gritty details regarding things like metadata generation, generating back-end queries based on URL parameters, etc.

As for the JavaScript client library, we’re leaving it out for now because, since OData is an HTTP-based protocol, we can use any REST library to access it.

3. An Olingo Java V2 Service

Let’s create a simple OData service with the two EntitySets that we’ve used in our brief introduction to the protocol itself. At its core, Olingo V2 is simply a set of JAX-RS resources and, as such, we need to provide the required infrastructure in order to use it. Namely, we need a JAX-RS implementation and a compatible servlet container.

For this example, we’ve opted to use Spring Boot – as it provides a quick way to create a suitable environment to host our service. We’ll also use Olingo’s JPA adapter, which “talks” directly to a user-supplied EntityManager in order to gather all data needed to create the OData’s EntityDataModel.

While not a strict requirement, including the JPA adapter greatly simplifies the task of creating our service.

Besides standard Spring Boot dependencies, we need to add a couple of Olingo’s jars:

<dependency>
    <groupId>org.apache.olingo</groupId>
    <artifactId>olingo-odata2-core</artifactId>
    <version>2.0.11</version>
    <exclusions>
        <exclusion>
            <groupId>javax.ws.rs</groupId>
            <artifactId>javax.ws.rs-api</artifactId>
         </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.apache.olingo</groupId>
    <artifactId>olingo-odata2-jpa-processor-core</artifactId>
    <version>2.0.11</version>
</dependency>
<dependency>
    <groupId>org.apache.olingo</groupId>
    <artifactId>olingo-odata2-jpa-processor-ref</artifactId>
    <version>2.0.11</version>
    <exclusions>
        <exclusion>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>eclipselink</artifactId>
        </exclusion>
    </exclusions>
</dependency>

The latest version of those libraries is available at Maven’s Central repository:

We need those exclusions in this list because Olingo has dependencies on EclipseLink as its JPA provider and also uses a different JAX-RS version than Spring Boot.

3.1. Domain Classes

The first step to implement a JPA-based OData service with Olingo is to create our domain entities. In this simple example, we’ll create just two classes – CarMaker and CarModel – with a single one-to-many relationship:

@Entity
@Table(name="car_maker")
public class CarMaker {    
    @Id @GeneratedValue(strategy=GenerationType.IDENTITY)    
    private Long id;
    @NotNull
    private String name;
    @OneToMany(mappedBy="maker",orphanRemoval = true,cascade=CascadeType.ALL)
    private List<CarModel> models;
    // ... getters, setters and hashcode omitted 
}

@Entity
@Table(name="car_model")
public class CarModel {
    @Id @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;
    
    @NotNull
    private String name;
    
    @NotNull
    private Integer year;
    
    @NotNull
    private String sku;
    
    @ManyToOne(optional=false,fetch=FetchType.LAZY) @JoinColumn(name="maker_fk")
    private CarMaker maker;
    
    // ... getters, setters and hashcode omitted
}

3.2. ODataJPAServiceFactory Implementation

The key component we need to provide to Olingo in order to serve data from a JPA domain is a concrete implementation of an abstract class called ODataJPAServiceFactory. This class should extend ODataServiceFactory and works as an adapter between JPA and OData. We’ll name this factory CarsODataJPAServiceFactory, after the main topic for our domain:

@Component
public class CarsODataJPAServiceFactory extends ODataJPAServiceFactory {
    // other methods omitted...

    @Override
    public ODataJPAContext initializeODataJPAContext() throws ODataJPARuntimeException {
        ODataJPAContext ctx = getODataJPAContext();
        ODataContext octx = ctx.getODataContext();
        HttpServletRequest request = (HttpServletRequest) octx.getParameter(
          ODataContext.HTTP_SERVLET_REQUEST_OBJECT);
        EntityManager em = (EntityManager) request
          .getAttribute(EntityManagerFilter.EM_REQUEST_ATTRIBUTE);
        
        ctx.setEntityManager(em);
        ctx.setPersistenceUnitName("default");
        ctx.setContainerManaged(true);                
        return ctx;
    }
}

Olingo calls the initializeJPAContext() method if this class to get a new ODataJPAContext  used to handle every OData request. Here, we use the getODataJPAContext() method from the base classe to get a “plain” instance which we then do some customization.

This process is somewhat convoluted, so let’s draw a UML sequence to visualize how all this happens:

Olingo Request Processing

Note that we’re intentionally using setEntityManager() instead of setEntityManagerFactory(). We could get one from Spring but, if we pass it to Olingo, it’ll conflict with the way that Spring Boot handles its lifecycle – especially when dealing with transactions.

For this reason, we’ll resort to pass an already existing EntityManager instance and inform it that its lifecycle its externally managed. The injected EntityManager instance comes from an attribute available at the current request. We’ll later see how to set this attribute.

3.3. Jersey Resource Registration

The next step is to register our ServiceFactory with Olingo’s runtime and register Olingo’s entry point with the JAX-RS runtime. We’ll do it inside a ResourceConfig derived class, where we also define the OData path for our service to be /odata:

@Component
@ApplicationPath("/odata")
public class JerseyConfig extends ResourceConfig {
    public JerseyConfig(CarsODataJPAServiceFactory serviceFactory, EntityManagerFactory emf) {        
        ODataApplication app = new ODataApplication();        
        app
          .getClasses()
          .forEach( c -> {
              if ( !ODataRootLocator.class.isAssignableFrom(c)) {
                  register(c);
              }
          });
        
        register(new CarsRootLocator(serviceFactory)); 
        register(new EntityManagerFilter(emf));
    }
    
    // ... other methods omitted
}

Olingo’s provided ODataApplication is a regular JAX-RS Application class that registers a few providers using the standard callback getClasses()

We can use all but the ODataRootLocator class as-is. This particular one is responsible for instantiating our ODataJPAServiceFactory implementation using Java’s newInstance() method. But, since we want Spring to manage it for us, we need to replace it by a custom locator.

This locator is a very simple JAX-RS resource that extends Olingo’s stock ODataRootLocator and it returns our Spring-managed ServiceFactory when needed:

@Path("/")
public class CarsRootLocator extends ODataRootLocator {
    private CarsODataJPAServiceFactory serviceFactory;
    public CarsRootLocator(CarsODataJPAServiceFactory serviceFactory) {
        this.serviceFactory = serviceFactory;
    }

    @Override
    public ODataServiceFactory getServiceFactory() {
       return this.serviceFactory;
    } 
}

3.4. EntityManager Filter

The last remaining piece for our OData service the EntityManagerFilter. This filter injects an EntityManager in the current request, so it is available to the ServiceFactory. It’s a simple JAX-RS @Provider class that implements both ContainerRequestFilter and ContainerResponseFilter interfaces, so it can properly handle transactions:

@Provider
public static class EntityManagerFilter implements ContainerRequestFilter, 
  ContainerResponseFilter {

    public static final String EM_REQUEST_ATTRIBUTE = 
      EntityManagerFilter.class.getName() + "_ENTITY_MANAGER";
    private final EntityManagerFactory emf;

    @Context
    private HttpServletRequest httpRequest;

    public EntityManagerFilter(EntityManagerFactory emf) {
        this.emf = emf;
    }

    @Override
    public void filter(ContainerRequestContext ctx) throws IOException {
        EntityManager em = this.emf.createEntityManager();
        httpRequest.setAttribute(EM_REQUEST_ATTRIBUTE, em);
        if (!"GET".equalsIgnoreCase(ctx.getMethod())) {
            em.getTransaction().begin();
        }
    }

    @Override
    public void filter(ContainerRequestContext requestContext, 
      ContainerResponseContext responseContext) throws IOException {
        EntityManager em = (EntityManager) httpRequest.getAttribute(EM_REQUEST_ATTRIBUTE);
        if (!"GET".equalsIgnoreCase(requestContext.getMethod())) {
            EntityTransaction t = em.getTransaction();
            if (t.isActive() && !t.getRollbackOnly()) {
                t.commit();
            }
        }
        
        em.close();
    }
}

The first filter() method, called at the start of a resource request, uses the provided EntityManagerFactory to create a new EntityManager instance, which is then put under an attribute so it can later be recovered by the ServiceFactory. We also skip GET requests since should not have any side effects, and so we won’t need a transaction.

The second filter()  method is called after Olingo has finished processing the request. Here we also check the request method, too, and commit the transaction if required.

3.5. Testing

Let’s test our implementation using simple curl commands. The first this we can do is get the services $metadata document:

curl http://localhost:8080/odata/$metadata

As expected, the document contains two types – CarMaker and CarModel – and an association. Now, let’s play a bit more with our service, retrieving top-level collections and entities:

curl http://localhost:8080/odata/CarMakers
curl http://localhost:8080/odata/CarModels
curl http://localhost:8080/odata/CarMakers(1)
curl http://localhost:8080/odata/CarModels(1)
curl http://localhost:8080/odata/CarModels(1)/CarMakerDetails

Now, let’s test a simple query returning all CarMakers where its name starts with ‘B’:

curl http://localhost:8080/odata/CarMakers?$filter=startswith(Name,'B')

A more complete list of example URLs is available at our OData Protocol Guide article.

5. Conclusion

In this article, we’ve seen how to create a simple OData service backed by a JPA domain using Olingo V2.

As of this writing, there is an open issue on Olingo’s JIRA tracking the works on a JPA module for V4, but the last comment dates back to 2016. There’s also a third-party open-source JPA adapter hosted at SAP’s GitHub repository which, although unreleased, seems to be more feature-complete at this point than Olingo’s one.

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)