Spring Boot 3.0 upgrade related issues
I am now upgrading to Spring Boot 2.7.6 and then upgrading to 3.0
Original version:
springboot 1.5.1.RELEASE + jdk1.8
Target version:
springboot 3.0 + jdk17
Notes:
1. org.apache.maven.plugins:maven
? If you refresh maven in the previous project, org.apache.maven.plugins:maven-xxxxxxx will appear. Add the following code to the maven configuration item
<mirror> <id>alimaven</id> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <mirrorOf>central</mirrorOf> </mirror> <!-- maven official image --> <mirror> <id>mirrorId</id> <mirrorOf>central</mirrorOf> <name>Human Readable Name</name> <url>http://repo1.maven.org/maven2/</url> </mirror> <!-- Alibaba Cloud Mirror --> <mirror> <id>alimaven</id> <name>aliyun maven</name> <url>http://central.maven.org/maven2</url> <mirrorOf>central</mirrorOf> </mirror> <!-- Alibaba Cloud Mirror --> <mirror> <id>alimaven</id> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/repositories/central/</url> <mirrorOf>central</mirrorOf> </mirror> <!-- junit mirror address --> <mirror> <id>junit</id> <name>junit Address/</name> <url>http://jcenter.bintray.com/</url> <mirrorOf>central</mirrorOf> </mirror>
2.{org.springframework.boot:spring-boot-starter-cloud-connectors:null:jar}: The version cannot be empty.**
? If you encounter an error that the org.springframework.boot:spring-boot-starter-cloud-connectors:null:jar version is empty when upgrading the Spring Boot version, it may be a problem caused by the version. This error usually occurs when upgrading a Spring Boot 1.x project to 2.x. You can check whether there is a specified version of spring-cloud-connectors
in the project. If not, you can manually add dependencies and specify the version. An example Maven dependency is as follows:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cloud-connectors</artifactId> <version>2.1.8.RELEASE</version> </dependency>
Problems caused by Spring Boot version differences
1.mapstruct** version (cannot find Mapper annotation, Mapping annotation)
? If mapstruct is referenced in the project, the mapstruct version needs to be upgraded to version 1.4.1 or higher. Currently, the version I choose is 1.4.2.Final< /strong>
? At the same time, we have upgraded the version of jdk, so we also need to make changes in the original dependencies
<!-- original version --> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-jdk8</artifactId> <version>${mapstruct.version}</version> </dependency> <!-- The new version can remove jdk8 --> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct</artifactId> <version>${mapstruct.version}</version> </dependency>
2. Pageable interface
? The Pageable interface is an interface defined in the spring Data library. This interface is an abstraction of all paging-related information. Through this interface, we can get all the information related to paging (such as pageNumber, pageSize, etc.).
? In this interface, the getOffset() method is mainly used to return the offset to be taken according to the base page and page size. Now due to the version upgrade, its return value is changed from int Type conversion to long, if this method is referenced in the code, you need to pay attention to type conversion.
The method findOne in 3.org.springframework.data.repository.query.QueryByExampleExecutor is applied to the given type;
? This is a problem caused by the version change. Then I called the org.springframework.data.repository package on the 1.5 version. After the upgrade, I need to change it to findById() .**orElse(null), because find.one is under the repository.query package, **will report an error.
? Similarly: the delete() method also has problems. If you delete one deleteById(), if you delete multiple, pass in the collection and usedeleteAll( );
4.com.mongodb.client.MongoCollection cannot be converted to com.mongodb.DBCollection**
DBCollection
is a class in the mongo-java-driver
package, which is used to operate the collection (Collection) in the MongoDB database. Since the release of MongoDB Java Driver 3.x, DBCollection
has been deprecated in favor of the MongoCollection
class. You can use the MongoCollection
class to replace DBCollection
, which provides better code compatibility and more features. Here is a sample code that demonstrates how to use MongoCollection
:
// 1. Create a MongoDB client instance MongoClient mongoClient = new MongoClient("localhost", 27017); // 2. Get the database MongoDatabase database = mongoClient. getDatabase("myDb"); // 3. Get the collection MongoCollection<Document> collection = database. getCollection("myCollection"); // 4. Insert document Document doc = new Document("name", "John Doe") .append("age", 30) .append("email", "[email protected]"); collection.insertOne(doc); // 5. Query documents Document query = new Document("name", "John Doe"); FindIterable<Document> results = collection. find(query); for (Document result : results) {<!-- --> System.out.println(result.toJson()); } // 6. Update the document Document updateQuery = new Document("name", "John Doe"); Document updateDoc = new Document("$set", new Document("age", 35)); UpdateResult updateResult = collection. updateOne(updateQuery, updateDoc); System.out.println("Update Count: " + updateResult.getModifiedCount()); // 7. Delete the document Document deleteQuery = new Document("name", "John Doe"); DeleteResult deleteResult = collection. deleteOne(deleteQuery); System.out.println("Delete Count: " + deleteResult.getDeletedCount()); // 8. Close the client mongoClient. close();
? Note, MongoCollection
uses generics, you need to specify the type of documents in the collection. In the sample code above, we used the Document type. If you want to use a custom Java type, you need to map it to MongoDB’s BSON format. You can use the Codec
interface provided by MongoDB to convert between Java types and BSON formats.
5.Relaxe*dPropertyResolver not found
? Instead of directly using the existing PropertySource interface for binding, Spring Boot 2.0 introduces a new ConfigurationPropertySource interface. We’ve introduced a new interface that gives us a reasonable place to enforce relaxed binding rules that were previously part of binder. The main API of the interface is very simple:
// Original code: RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(environment, "spring. datasource"); propertyResolver. getSubProperties("....") // current code: Iterable sources = ConfigurationPropertySources. get(environment); Binder binder = new Binder(sources); BindResult bindResult = binder.bind("spring.datasource", Properties.class); Properties properties = bindResult. get();
6.reids could not be found (JedisPool could not be found)
After the version is upgraded, jedis needs to be re-introduced
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.10.2</version> </dependency>
Remarks: The version needs to be adjusted according to your own needs
7. EmbeddedServletContainerCustomizer, UndertowEmbeddedServletContainerFactory interface could not be found
? Starting with Spring Boot 2.0 version, the EmbeddedServletContainerCustomizer
interface is obsolete and deprecated. In Spring Boot 2.0 and later versions, it is recommended to use the WebServerFactoryCustomizer
interface to customize the embedded web server. If the EmbeddedServletContainerCustomizer
interface cannot be found after upgrading the Spring Boot version, you can try to replace it with the WebServerFactoryCustomizer
interface, and the UndertowEmbeddedServletContainerFactory
interface can Replace with UndertowServletWebServerFactory
, and modify the method signature accordingly. Here are some possible solutions:
public class WebConfigurer implements ServletContextInitializer, WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {<!-- --> @Override public void customize(ConfigurableServletWebServerFactory container) {<!-- --> MimeMappings mappings = new MimeMappings(MimeMappings. DEFAULT); // IE issue, see https://github.com/jhipster/generator-jhipster/pull/711 mappings.add("html", "text/html;charset=utf-8"); // CloudFoundry issue, see https://github.com/cloudfoundry/gorouter/issues/64 mappings.add("json", "text/html;charset=utf-8"); container.setMimeMappings(mappings); /* * Enable HTTP/2 for Undertow - https://twitter.com/ankinson/status/829256167700492288 * HTTP/2 requires HTTPS, so HTTP requests will fallback to HTTP/1.1. * See the JHipsterProperties class and your application-*.yml configuration files * for more information. */ if (jHipsterProperties.getHttp().getVersion().equals(JHipsterProperties.Http.Version.V_2_0)) {<!-- --> if (container instanceof UndertowServletWebServerFactory) {<!-- --> ((UndertowServletWebServerFactory) container) .addBuilderCustomizers((builder) -> {<!-- --> builder.setServerOption(UndertowOptions.ENABLE_HTTP2, true); }); } } } }
8. ExportMetricReader, ExportMetricWriter annotations could not be found
In Spring Boot 2.7, the @ExportMetrics
and @ExportMetricWriter
annotations have indeed been removed. If you want to export a custom MeterRegistry
instance for use by other beans, you can consider using the MeterRegistryPostProcessor
interface or the MeterRegistryCustomizer
interface. The MeterRegistryPostProcessor
interface is used for post-processing when the container loads the MeterRegistry
instance, which can be used to export the MeterRegistry
instance to other components. Here is an example:
@Configuration public class MyMetricsConfig {<!-- --> @Bean public PrometheusMeterRegistry myMeterRegistry() {<!-- --> return new PrometheusMeterRegistry(PrometheusConfig. DEFAULT); } @Bean public MeterRegistryPostProcessor myMeterRegistryPostProcessor(PrometheusMeterRegistry myMeterRegistry) {<!-- --> return (registry) -> {<!-- --> registry.add(myMeterRegistry); }; } } @Service @MicrometerMetrics public class MyService {<!-- --> private final MeterRegistry meterRegistry; @Autowired public MyService(MeterRegistry meterRegistry) {<!-- --> this.meterRegistry = meterRegistry; } //... }
? In the above example, a PrometheusMeterRegistry
instance named myMeterRegistry
is defined in the MyMetricsConfig
configuration class, and the myMeterRegistryPostProcessor
The code> method creates a MeterRegistryPostProcessor
instance to export myMeterRegistry
to other components. The MeterRegistryCustomizer
interface is used for post-processing when the container loads the MeterRegistry
instance, through which some properties of the MeterRegistry
instance can be customized. Here is an example:
@Configuration public class MyMetricsConfig {<!-- --> @Bean public PrometheusMeterRegistry myMeterRegistry() {<!-- --> return new PrometheusMeterRegistry(PrometheusConfig. DEFAULT); } @Bean public MeterRegistryCustomizer<PrometheusMeterRegistry> myMeterRegistryCustomizer() {<!-- --> return (registry) -> {<!-- --> registry.config().commonTags("application", "myapp"); }; } } @Service @MicrometerMetrics public class MyService {<!-- --> private final MeterRegistry meterRegistry; @Autowired public MyService(MeterRegistry meterRegistry) {<!-- --> this.meterRegistry = meterRegistry; } //... }
? In the above example, a PrometheusMeterRegistry
instance named myMeterRegistry
is defined in the MyMetricsConfig
configuration class, and myMeterRegistryCustomizer
The code> method creates a MeterRegistryCustomizer
instance, adding a generic tag named application
with a value of myapp
.
9.JmxReporter class not found
The class JmxReporter is missing, and it is in the package com.codahale.metrics
Just import a dependency directly to solve
<dependency> <groupId>com.codahale.metrics</groupId> <artifactId>metrics-core</artifactId> <version>3.0.2</version> </dependency>
10.getErrorAttributes() method is rewritten
? In Spring Boot 2.7, the getErrorAttributes()
method has been removed, and it is recommended to use the getErrorAttributes(WebRequest, ErrorAttributeOptions)
method. The return value type of the getErrorAttributes(WebRequest, ErrorAttributeOptions)
method is Map
. ErrorAttributeOptions
is an enumeration type, representing the options of error attributes, you can use the ErrorAttributeOptions.defaults()
method to get the default option value. You can set whether to include stack trace information, exception type and other information in the options. Here is a sample code using the getErrorAttributes(WebRequest, ErrorAttributeOptions)
method:
@ControllerAdvice public class MyErrorController implements ErrorController {<!-- --> private static final String PATH = "/error"; @Override public String getErrorPath() {<!-- --> return PATH; } @RequestMapping(PATH) public ResponseEntity<Map<String, Object>> error(WebRequest webRequest) {<!-- --> ErrorAttributeOptions options = ErrorAttributeOptions. defaults() .including(ErrorAttributeOptions.Include.STACK_TRACE); Map<String, Object> errorAttributes = new DefaultErrorAttributes() .getErrorAttributes(webRequest, options); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorAttributes); } }
? In the above code, we override the getErrorPath()
method of the ErrorController
interface, specifying the path of the error endpoint as /error
. In the error()
method, we create an ErrorAttributeOptions
object and specify to include the stack trace. Then use the instance of DefaultErrorAttributes
to call the getErrorAttributes(WebRequest, ErrorAttributeOptions)
method to get the error attributes, and finally use ResponseEntity
to return the error attribute Map
code> . It should be noted that DefaultErrorAttributes
is a default error attribute parser, which parses error information into a Map
object. If you need to customize error attributes, you can create a class that implements the ErrorAttributes
interface and use it in the controller.
11. Rewrite the size of the uploaded data in the MultipartConfigFactory class
//In the original method, we can directly define MultipartConfigFactory factory = new MultipartConfigFactory(); factory.setMaxFileSize("100MB"); factory.setMaxRequestSize("100MB"); // now to rewrite factory.setMaxFileSize( DataSize.parse("100", DataUnit.MEGABYTES)); factory.setMaxRequestSize( DataSize.parse("100", DataUnit.MEGABYTES));
-
PageRequest
class constructor changed from public access to protected accessThe constructor of the
PageRequest
class has changed from public access to protected access, and can no longer be directly called externally. If you used thePageRequest
constructor in your previous code, you need to modify it as follows:You can use its static method PageRequest.of() to have the same effect as new PageReques()
- First, create a subclass that inherits from
PageRequest
as follows:
- First, create a subclass that inherits from
public class CustomPageRequest extends PageRequest {<!-- --> public CustomPageRequest(int page, int size) {<!-- --> super(page, size); } public CustomPageRequest(int page, int size, Sort.Direction direction, String... properties) {<!-- --> super(page, size, direction, properties); } }
In this subclass, we inherit PageRequest
and provide two construction methods, through which new paging request objects can be created. 2. Then, where PageRequest
was used before, replace it with the CustomPageRequest
we created, as shown below:
Pageable pageable = new CustomPageRequest(pageNumber, pageSize);
or:
Pageable pageable = new CustomPageRequest(pageNumber, pageSize, Sort.Direction.ASC, "id");
This allows you to continue using the paging request object in your code. It should be noted that if there are many places in your code to create paging request objects, you need to replace all places.
Similarly, the sort class has also changed, for example:
//Writing before Sort sort = new Sort( direction, properties) // can now be called statically by(Sdirection, properties);