I have a project named customer
written in spring boot, and another maven project named customer-customization
adds the customer
project as a dependency and uses it. My goal: To change the rest service. As the name of the project suggests, I want to allow the project to be used by making changes without touching my source code.
Customer project
Spring boot version : 3.2.2
Java version: 21
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
CityService.java
@RequestMapping("city")
public interface CityService {
@PostMapping(value = "/createCity", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
ResponseEntity<CityDto> createCity(@RequestBody CityDto param);
}
CityServiceImpl.java
@RestController
public class CityServiceImpl implements CityService {
@Override
public ResponseEntity<CityDto> createCity(CityDto param) {
...
}
}
customer-customization project
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.rz.customer</groupId>
<artifactId>customer-customization</artifactId>
<packaging>jar</packaging>
<version>0.0.1-alpha.1</version>
<name>Customer Customization</name>
<properties>
<start-class>com.rz.customer.app.CustomerCustomizationApplication</start-class>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<customer.version>0.0.1-alpha.1</customer.version>
</properties>
<dependencies>
<dependency>
<groupId>com.rz.customer</groupId>
<artifactId>customer-app</artifactId>
<version>${customer.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<mainClass>com.rz.customer.app.CustomerCustomizationApplication</mainClass>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
CustomCityService.java
@RequestMapping("city")
public interface CustomCityService {
@PostMapping(value = "/createCity", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
ResponseEntity<CustomCityDto> createCity(@RequestBody CustomCityDto param);
}
CustomCityServiceImpl.java
@RestController
public class CustomCityServiceImpl implements CustomCityService {
@Override
public ResponseEntity<CityDto> createCity(CustomCityDto param) {
...
}
}
While running the customer-customization
project
I'm getting this error:
"Caused by: java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'customCityServiceImpl' method
com.rz.customer.controller.impl.CustomCityServiceImpl#createCity(CityInputDto)
to {POST [/city/createCity], consumes [application/json], produces [application/json]}: There is already 'customCityServiceImpl' bean method
com.rz.customer.controller.impl.CustomCityServiceImpl#createCity(CustomCityDto)"
I know this error is normal because there cannot be more than one service belonging to the same url.
My goal is somehow I want the customer-customization
project to overwhelm the service in the customer project.
I tried extending the RequestMappingHandlerMapping class but I couldn't. Is it possible to do this, perhaps by adding notation like @Primary to the CustomCityService.java
class and prioritizing it, or some other way?
Since my goal is to have the customer
project done without touching the source code, I want to make this change in the customer-customization
project.
How can I do?
I solved my problem with registerHandlerMethod
method of the RequestMappingHandlerMapping
class.
@Configuration
public class CustomRequestMappingHandlerMapping implements WebMvcRegistrations {
@Override
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
return new RequestMappingHandlerMapping() {
@Override
protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
Set<RequestMethod> httpMethods = mapping.getMethodsCondition().getMethods();
if (handler.toString().equals("cityServiceImpl") && httpMethods.contains(RequestMethod.POST)
&& mapping.getPatternValues().contains("/city/createCity")) {
return;
}
super.registerHandlerMethod(handler, method, mapping);
}
};
}
}