Spring Boot3.0 upgrade related issues

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));
  1. PageRequest class constructor changed from public access to protected access

    The constructor of the PageRequest class has changed from public access to protected access, and can no longer be directly called externally. If you used the PageRequest 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()

    1. First, create a subclass that inherits from PageRequest as follows:
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);
syntaxbug.com © 2021 All Rights Reserved.