Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release/update 2.x.x #419

Merged
merged 58 commits into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
5252c7b
Update version to 2.2.0-SNAPSHOT (#302)
wog48 Apr 24, 2024
cb9c0c1
Bump flyway.version from 10.11.0 to 10.11.1 in /jpa (#295)
dependabot[bot] May 6, 2024
541120f
Bump org.slf4j:slf4j-api from 2.0.9 to 2.0.13 in /jpa (#296)
dependabot[bot] May 6, 2024
d4baffc
Bump org.sonarsource.scanner.maven:sonar-maven-plugin in /jpa (#297)
dependabot[bot] May 6, 2024
56018de
Bump org.jacoco:jacoco-maven-plugin from 0.8.11 to 0.8.12 in /jpa (#298)
dependabot[bot] May 6, 2024
4fbf0c3
Bump com.fasterxml.jackson:jackson-bom from 2.16.0 to 2.17.1 in /jpa …
dependabot[bot] May 6, 2024
971b9cf
Fix issue 292
wog48 May 18, 2024
35b8192
Update version to 2.1.2 (#317)
wog48 May 26, 2024
de6ee8e
Bump org.slf4j:slf4j-simple from 2.0.9 to 2.0.13 in /jpa (#312)
dependabot[bot] May 26, 2024
54537c4
Bump org.pitest:pitest-maven from 1.15.3 to 1.16.1 in /jpa (#310)
dependabot[bot] May 26, 2024
6f4507a
Bump org.mockito:mockito-core from 5.11.0 to 5.12.0 in /jpa (#313)
dependabot[bot] May 26, 2024
c73050f
Bump flyway.version from 10.11.1 to 10.13.0 in /jpa (#315)
dependabot[bot] May 26, 2024
4b7043d
Bump org.springframework:spring-jcl from 6.1.4 to 6.1.8 in /jpa (#320)
dependabot[bot] May 26, 2024
78a131d
Bump org.sonarsource.scanner.maven:sonar-maven-plugin in /jpa (#328)
dependabot[bot] Jun 16, 2024
2ab1b7d
Bump org.eclipse.persistence:org.eclipse.persistence.jpa in /jpa (#321)
dependabot[bot] Jun 21, 2024
fccae05
Bump com.tngtech.archunit:archunit-junit5 from 1.2.1 to 1.3.0 in /jpa…
dependabot[bot] Jun 21, 2024
b7a2b26
Bump io.netty:netty-codec-http in /jpa (#332)
dependabot[bot] Jun 21, 2024
6dda210
Bump flyway.version from 10.13.0 to 10.15.0 in /jpa (#333)
dependabot[bot] Jun 21, 2024
5175907
Bugfix #325 - Add support for filtering by lambda operator on collect…
dbhandari555 Jun 23, 2024
22f6bf3
Bump jakarta.servlet:jakarta.servlet-api from 6.0.0 to 6.1.0 in /jpa …
dependabot[bot] Jun 27, 2024
ec02b4d
Bump org.springframework:spring-jcl from 6.1.8 to 6.1.10 in /jpa (#336)
dependabot[bot] Jun 27, 2024
3620f72
Bump org.hsqldb:hsqldb from 2.7.2 to 2.7.3 in /jpa (#337)
dependabot[bot] Jun 27, 2024
ad29d4c
Bump org.apache.maven.plugins:maven-surefire-plugin in /jpa (#338)
dependabot[bot] Jun 27, 2024
20b06f8
Defect/version 2.1.3 (#339)
wog48 Jun 29, 2024
ef67b7e
Defect/version 2.1.3 (#340)
wog48 Jun 29, 2024
f8cbf60
Update version to 2.2.0-SNAPSHOT (#342)
wog48 Jun 29, 2024
05475c6
Bump org.junit.jupiter:junit-jupiter from 5.10.2 to 5.10.3 in /jpa (#…
dependabot[bot] Aug 5, 2024
728bc81
Bump org.codehaus.mojo:versions-maven-plugin in /jpa (#349)
dependabot[bot] Aug 5, 2024
26e1120
Bump org.junit.platform:junit-platform-launcher in /jpa (#346)
dependabot[bot] Aug 5, 2024
531e695
Bump org.jacoco:jacoco-maven-plugin from 0.8.11 to 0.8.12 in /jpa (#345)
dependabot[bot] Aug 5, 2024
921cfed
Bump org.codehaus.mojo:versions-maven-plugin in /jpa (#343)
dependabot[bot] Aug 5, 2024
decffc8
Feature/version 2.2.0 (#353)
wog48 Aug 6, 2024
5a3bdfb
Bump org.slf4j:slf4j-api from 2.0.9 to 2.0.16 in /jpa (#357)
dependabot[bot] Aug 28, 2024
db21ba7
Bump io.netty:netty-codec-http in /jpa (#356)
dependabot[bot] Aug 28, 2024
ac86822
Bump org.apache.commons:commons-lang3 from 3.14.0 to 3.16.0 in /jpa (…
dependabot[bot] Aug 28, 2024
651a787
Bump flyway.version from 10.15.0 to 10.17.2 in /jpa (#364)
dependabot[bot] Sep 2, 2024
b12e2ea
Bump org.junit.jupiter:junit-jupiter from 5.10.3 to 5.11.0 in /jpa (#…
dependabot[bot] Sep 2, 2024
4676150
Bump org.apache.commons:commons-lang3 from 3.16.0 to 3.17.0 in /jpa (…
dependabot[bot] Sep 2, 2024
0d199a4
Update contribution guideline (#369)
wog48 Sep 10, 2024
64cdec3
Bump org.mockito:mockito-core from 5.12.0 to 5.13.0 in /jpa (#366)
dependabot[bot] Sep 10, 2024
5bb572c
Bump io.netty:netty-codec-http in /jpa (#367)
dependabot[bot] Sep 10, 2024
58d2a2d
Bump org.slf4j:slf4j-simple from 2.0.13 to 2.0.16 in /jpa (#368)
dependabot[bot] Sep 10, 2024
3ea39ae
Feature/add documentation (#370)
wog48 Sep 19, 2024
0438149
Feature/version 2.2.0 (#379)
wog48 Sep 23, 2024
978d183
Feature/version 2.2.0 (#386)
wog48 Oct 6, 2024
bf922f7
Feature/version 2.2.0 (#389)
wog48 Oct 7, 2024
8297765
Feature/version 2.2.0 (#394)
wog48 Oct 17, 2024
59c7610
Merge remote-tracking branch 'public/main' into release/update-2.x.x
wog48 Oct 18, 2024
3b3f31f
Update version to 2.3.0-SNAPSHOT (#399)
wog48 Oct 18, 2024
99026b1
Feature/version 2.3.0 (#402)
wog48 Nov 14, 2024
cd7bba9
Update sonar.yml
wog48 Nov 14, 2024
d1e6e15
Check for non empty root results in navigation request processor (#408)
dbhandari555 Nov 15, 2024
4232e3f
Chore(deps): Bump flyway.version from 10.20.0 to 10.21.0 in /jpa (#410)
dependabot[bot] Nov 16, 2024
1789eb0
Chore(deps): Bump io.netty:netty-codec-http in /jpa (#409)
dependabot[bot] Nov 16, 2024
be7c7c0
Feature/version 2.3.0 (#414)
wog48 Nov 21, 2024
33c31fb
Feature/version 2.3.0 (#415)
wog48 Nov 22, 2024
abe39ec
Merge remote-tracking branch 'public/release/2.x.x' into release/upda…
wog48 Nov 22, 2024
1affd10
Merge remote-tracking branch 'public/main' into release/update-2.x.x
wog48 Nov 22, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/sonar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,6 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_PROJECT: ${{secrets.SONAR_PROJECT}}
SONAR_ORG: ${{vars.SONAR_ORG}}
SONAR_ORG: ${{secrets.SONAR_ORG}}
SONAR_URL: https://sonarcloud.io
run: cd ./jpa && mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.organization=${SONAR_ORG} -Dsonar.projectKey=${SONAR_PROJECT} -Dsonar.host.url=${SONAR_URL} -Dsonar.projectKey=SAP_olingo-jpa-processor-v4 -Dsonar.token=${SONAR_TOKEN}
4 changes: 1 addition & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ tmp/
*.md.html
local.properties
.loadpath

# Eclipse Core


# External tool builders
.externalToolBuilders/

Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
[![REUSE status](https://api.reuse.software/badge/github.com/SAP/olingo-jpa-processor-v4)](https://api.reuse.software/info/github.com/SAP/olingo-jpa-processor-v4)
![GitHub last commit (develop)](https://img.shields.io/github/last-commit/SAP/OLINGO-JPA-PROCESSOR-V4/main.svg)
[![GitHub release](https://img.shields.io/github/release-pre/sap/olingo-jpa-processor-v4.svg?color=orange&label=release)](https://github.com/SAP/olingo-jpa-processor-v4/releases/)
[![Project Map](https://sourcespy.com/shield.svg)](https://sourcespy.com/github/sapolingojpaprocessorv4/)

The JPA Processor shall fill the gap between [Olingo V4](https://olingo.apache.org/doc/odata4/index.html) and the database, if [JPA](https://en.wikipedia.org/wiki/Java_Persistence_API) is used for object-relational mapping. If you want to be updated about Olingo changes subscribe to Olingo's [user mailing list]([email protected]).

Expand Down Expand Up @@ -47,7 +46,7 @@ clone the repository, import the projects and declare a dependency to either the
<dependency>
<groupId>com.sap.olingo</groupId>
<artifactId>odata-jpa-metadata</artifactId>
<version>2.2.0</version>
<version>2.3.0</version>
</dependency>
```

Expand All @@ -57,7 +56,7 @@ Or to the complete processor:
<dependency>
<groupId>com.sap.olingo</groupId>
<artifactId>odata-jpa-processor</artifactId>
<version>2.2.0</version>
<version>2.3.0</version>
</dependency>
```

Expand Down Expand Up @@ -103,4 +102,5 @@ Detailed information including third-party components and their licensing/copyri
|2.1.0| - Enhancement of annotation API<br>- Enhancement of API for server driven paging<br>- Optional support of IN operand <br>- Update to Olingo 5.0.0<br>- Rework $count implementation<br>- Fix problem with $count on collection properties|No|
|2.1.1| - Fix for issue [#292](https://github.com/SAP/olingo-jpa-processor-v4/issues/292)|No|
|2.1.3| - Fix for issue [#319](https://github.com/SAP/olingo-jpa-processor-v4/issues/319)<br> - Fix for issue [#325](https://github.com/SAP/olingo-jpa-processor-v4/issues/325)<br> - Fix for issue [#327](https://github.com/SAP/olingo-jpa-processor-v4/issues/327)<br> - Fix for issue [#331](https://github.com/SAP/olingo-jpa-processor-v4/issues/331)<br> - Fix of en issue with $orderby and _to one_ navigation properties |No|
|2.2.0| - Fix for issue [#378](https://github.com/SAP/olingo-jpa-processor-v4/issues/378)<br> - Fix for issue [#376](https://github.com/SAP/olingo-jpa-processor-v4/issues/376)<br> - Fix for issue [#361](https://github.com/SAP/olingo-jpa-processor-v4/issues/361)<br> - Fix for issue [#352](https://github.com/SAP/olingo-jpa-processor-v4/issues/352)<br> - Fix for issue [#307](https://github.com/SAP/olingo-jpa-processor-v4/issues/307) <br> - Enhancement according to [#314](https://github.com/SAP/olingo-jpa-processor-v4/issues/314)|No|
|2.2.0| - Fix for issue [#378](https://github.com/SAP/olingo-jpa-processor-v4/issues/378)<br> - Fix for issue [#378](https://github.com/SAP/olingo-jpa-processor-v4/issues/378)<br> - Fix for issue [#361](https://github.com/SAP/olingo-jpa-processor-v4/issues/361)<br> - Fix for issue [#352](https://github.com/SAP/olingo-jpa-processor-v4/issues/352)<br> - Fix for issue [#307](https://github.com/SAP/olingo-jpa-processor-v4/issues/307) <br> - Enhancement according to [#314](https://github.com/SAP/olingo-jpa-processor-v4/issues/314)|No|
|2.3.0| - Add support for handling multiple API version. Issue [#308](https://github.com/SAP/olingo-jpa-processor-v4/issues/308)<br> - Fix for issue [#359](https://github.com/SAP/olingo-jpa-processor-v4/issues/359)<br> - Fix for issue [#406](https://github.com/SAP/olingo-jpa-processor-v4/issues/406)<br> - Fix for issue [#397](https://github.com/SAP/olingo-jpa-processor-v4/issues/397)|No|
6 changes: 3 additions & 3 deletions jpa-archetype/odata-jpa-archetype-spring/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>com.sap.olingo</groupId>
<artifactId>odata-jpa-archetype</artifactId>
<version>2.2.0</version>
<version>2.3.0</version>
</parent>
<artifactId>odata-jpa-archetype-spring</artifactId>
<name>Archetype - odata-jpa-archetype-spring</name>
Expand All @@ -17,15 +17,15 @@
<extension>
<groupId>org.apache.maven.archetype</groupId>
<artifactId>archetype-packaging</artifactId>
<version>3.3.0</version>
<version>3.3.1</version>
</extension>
</extensions>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-archetype-plugin</artifactId>
<version>3.3.0</version>
<version>3.3.1</version>
<configuration>
<debug>true</debug>
</configuration>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
</parent>

<properties>
<processor.version>2.2.0</processor.version>
<processor.version>2.3.0</processor.version>
<java.version>17</java.version>
<build.sourceEncoding>UTF-8</build.sourceEncoding>
<eclipselink.version>4.0.3</eclipselink.version>
Expand Down
7 changes: 3 additions & 4 deletions jpa-archetype/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.sap.olingo</groupId>
<artifactId>odata-jpa-archetype</artifactId>
<version>2.2.0</version>
<version>2.3.0</version>
<packaging>pom</packaging>
<url>https://github.com/SAP/olingo-jpa-processor-v4</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.build.source>17</project.build.source>
<odata.jpa.version>2.2.0</odata.jpa.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.build.source>17</project.build.source>
</properties>

<modules>
Expand Down
274 changes: 274 additions & 0 deletions jpa-tutorial/Questions/HowToHandleApiVersions.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,274 @@
= How to handle multiple API versions?

== Introduction

During the lifetime of an API it can happen that the API needs to be adopted. Some of these adoptions are incompatible.
That is, a client needs to be adopted as well to be able to handle the change. Typical incompatible changes are:

* Making a property mandatory.
* Changing the name of a property.
* Combining two properties or splitting a property.
* Removing an entity or an operation.
* ...

But even adding a non mandatory property can be incompatible in case a client can not handle unknown properties.
In all these cases the server has to provide two versions of the API till all clients have been adopted.
Starting with release 2.3.0 the JPA Processor supports multiple versions.

== Basic Idea

Instead of having a version annotation at the entities, the JPA Processor make use of multiple sets of JPA metadata.
An annotation has the risks that all entities need to be copied if one must be changed.

Metadata are (mainly) provided by the entity manager factory, so multiple entity manager factory are needed.
An option is to create multiple persistence units in the persistence.xml.
Using Spring Boot, we have also another option, which will be described below.

== Implementation


We assume that each entity or each aggregate has an own package e.g. `...model.tip` for the Trip entity and `...model.person` for the Person.
In case we like to create a new version of Trip, we need to create a new package e.g. `...model.v2.trip` and create the new version of the entity within it.

Using Spring Boot we need to make some preparation. First step is to deactivate https://www.baeldung.com/spring-open-session-in-vie[spring open session in view],
as we may get trouble having multiple beans for the entity manager factory. So we add the following to the application.yml or the corresponding to the application.properties:

[source, yaml]
----
spring:
jpa:
open-in-view: false
----

Next, we need to rearrange the creation of the entity manager factory.
First step is to create an abstract super class with the basic settings and a creation of the transaction manager:

[source, java]
----
public abstract class EclipseLinkJpaConfiguration extends JpaBaseConfiguration {

protected EclipseLinkJpaConfiguration(final DataSource dataSource, final JpaProperties properties,
final ObjectProvider<JtaTransactionManager> jtaTransactionManager) {
super(dataSource, properties, jtaTransactionManager);
}

@Override
protected AbstractJpaVendorAdapter createJpaVendorAdapter() {
return new EclipseLinkJpaVendorAdapter();
}

@Override
protected Map<String, Object> getVendorProperties() {
// https://stackoverflow.com/questions/10769051/eclipselinkjpavendoradapter-instead-of-hibernatejpavendoradapter-issue
final HashMap<String, Object> jpaProperties = new HashMap<>();
jpaProperties.put(WEAVING, "false");
// No table generation by JPA
jpaProperties.put(DDL_GENERATION, "none");
jpaProperties.put(LOGGING_LEVEL, SessionLog.FINE_LABEL);
jpaProperties.put(TRANSACTION_TYPE, "RESOURCE_LOCAL");
// do not cache entities locally, as this causes problems if multiple application instances are used
jpaProperties.put(CACHE_SHARED_DEFAULT, "false");
// You can also tweak your application performance by configuring your database connection pool.
// https://www.eclipse.org/eclipselink/documentation/2.7/jpa/extensions/persistenceproperties_ref.htm#connectionpool
jpaProperties.put(CONNECTION_POOL_MAX, 50);
return jpaProperties;
}

String[] getMapping() {
final List<String> mappingResources = this.getProperties().getMappingResources();
return (!ObjectUtils.isEmpty(mappingResources) ? StringUtils.toStringArray(mappingResources) : null);
}

PlatformTransactionManager createTransactionManager(
final ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers,
final EntityManagerFactory entityManagerFactory) {

final JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
transactionManagerCustomizers
.ifAvailable((customizers) -> customizers.customize((TransactionManager) transactionManager));
return transactionManager;
}

Builder basicSettings(final EntityManagerFactoryBuilder factoryBuilder) {
final Map<String, Object> vendorProperties = getVendorProperties();
customizeVendorProperties(vendorProperties);
return factoryBuilder
.dataSource(this.getDataSource())
.properties(vendorProperties)
.mappingResources(getMapping())
.jta(false);
}
}
----

Then we need to create the version specific entity manager factories.
Please note that with each version of the entity manager factory we also have to create a transaction manager.
It is also important that one of the beans for the factory has the name `entityManagerFactory`.
First the entity manager factory for the old version:

[source, java]
----
...
import org.example.model.planitem.PlanItem;
import org.example.model.trip.Trip;
...
@Configuration
public class JpaConfigurationV1 extends EclipseLinkJpaConfiguration {

protected JpaConfigurationV1(final DataSource dataSource, final JpaProperties properties,
final ObjectProvider<JtaTransactionManager> jtaTransactionManager) {
super(dataSource, properties, jtaTransactionManager);
}

@Bean("transactionManagerFactoryV1")
PlatformTransactionManager transactionManager(
final ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers,
@Qualifier("entityManagerFactory") final EntityManagerFactory entityManagerFactory) {

return createTransactionManager(transactionManagerCustomizers, entityManagerFactory);
}

@Override
@Bean("entityManagerFactory") // A bean with this name is needed
public LocalContainerEntityManagerFactoryBean entityManagerFactory(final EntityManagerFactoryBuilder factoryBuilder,
final PersistenceManagedTypes persistenceManagedTypes) {

return basicSettings(factoryBuilder)
.packages(Trip.class, PlanItem.class, OffsetDateTimeConverter.class)
.build();
}
}
----

And then the entity manager factory for the new version.
You need to look carefully to see the difference beside the bean names.
The important call here is in `entityManagerFactory`.
We provide the `EntityManagerFactoryBuilder` classes that represent the packages that contain the JPA entities.
The difference is that Trip is now in a different package.

[source, java]
----
...
import org.example.model.planitem.PlanItem;
import org.example.model.v2.trip.Trip;
...
@Configuration
public class JpaConfigurationV2 extends EclipseLinkJpaConfiguration {

protected JpaConfigurationV2(final DataSource dataSource, final JpaProperties properties,
final ObjectProvider<JtaTransactionManager> jtaTransactionManager) {
super(dataSource, properties, jtaTransactionManager);
}

@Bean("transactionManagerFactoryV2")
PlatformTransactionManager transactionManager(
final ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers,
@Qualifier("entityManagerFactoryV2") final EntityManagerFactory entityManagerFactoryV2) {

return createTransactionManager(transactionManagerCustomizers, entityManagerFactoryV2);
}

@Override
@Bean("entityManagerFactoryV2")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(final EntityManagerFactoryBuilder factoryBuilder,
final PersistenceManagedTypes persistenceManagedTypes) {

return basicSettings(factoryBuilder)
.packages(Trip.class, PlanItem.class, OffsetDateTimeConverter.class)
.build();
}
}
----

Now the JPA Processor needs to know that it has to handle multiple versions.
The versions are defined in the session context, which we create in `ProcessorConfiguration`.
A description for a versions contains of:

* An id to identify the version later.
* The instance of the version specific entity manager factory.
* The version specific request mapping path, which is needed to make Olingo work together with Spring.
* The (type) packages containing the enumerations and operations.
* The metadata post processor

[IMPORTANT]
====
In case there are bound operations, so functions or actions, for the changed entity, also these
need to be adjusted and the corresponding packages need to be provided.

====

Here we only look at the bare minimum:

[source, java]
----
@Bean
JPAODataSessionContextAccess sessionContext(
@Qualifier("entityManagerFactoryV2") final EntityManagerFactory entityManagerFactoryV2,
@Qualifier("entityManagerFactory") final EntityManagerFactory entityManagerFactoryV1) throws ODataException {

return JPAODataServiceContext.with()
...
.setVersions(
JPAApiVersion.with()
.setId("V1")
.setEntityManagerFactory(entityManagerFactoryV1)
.setRequestMappingPath("Trippin/v1")
.build(),
JPAApiVersion.with()
.setId("V2")
.setEntityManagerFactory(entityManagerFactoryV2)
.setRequestMappingPath("Trippin/v2")
.build())
...
----

[NOTE]
====
There are also setters for all the information provided with a version.
In case a version is provided this is taken.
Otherwise, the information from the setter.
====


With this the design time part is finished and we have to adopt the runtime part.
For each request we need to decide if it is for version one or for version two.
This is done by checking if the request URI is for version one or two.
The version id we have determined is provided to the request context:

[source, java]
----
@Bean
@Scope(scopeName = SCOPE_REQUEST)
JPAODataRequestContext requestContext() {

final HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
.getRequest();

return JPAODataRequestContext.with()
...
.setVersion(determineVersion(request))
.build();
}

private String determineVersion(final HttpServletRequest request) {
return request.getRequestURI().toUpperCase().startsWith("/TRIPPIN/V2/") ? "V2" : "V1";
}
----

As a last step we have to adopt the controller, so that it accepts requests for all versions.
Alternatively, we could also create a separate controller, so we would have one accepting requests
for version 1 and one accepting requests for version 2.
But to keep things simple, we just change annotation `@RequestMapping`:

[source, java]
----
@RestController
@RequestMapping("Trippin/")
@RequestScope
public class ODataController {
...
}
----

Now we can start the service and perform requests like: `/Trippin/v1/$metadata` or `/Trippin/v2/$metadata`.
1 change: 1 addition & 0 deletions jpa-tutorial/Questions/Questions.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Having done that, we are ready to go ahead:
. xref:HowToMakeUseOfAnnotations.adoc[How to make use of Annotations?]
. xref:HowToBuildServerDrivenPaging.adoc[How to build server-driven paging?]
. xref:HowToBuildServerDrivenPagingExpand.adoc[How to build server driven-paging for $expand?]
. xref:HowToHandleApiVersions.adoc[How to handle multiple API versions?]

Some things that are good to know:

Expand Down
2 changes: 1 addition & 1 deletion jpa/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ target/
.settings/
.metadata
*.log
/.dbeaver/
/old.project
/Scripts/
/.dbeaver/
Loading