View Javadoc
1   /*
2   * Copyright 2019-2026 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.bremersee.exception.spring.boot.autoconfigure.servlet;
18  
19  import java.util.List;
20  import org.apache.commons.logging.Log;
21  import org.apache.commons.logging.LogFactory;
22  import org.bremersee.exception.RestApiExceptionMapper;
23  import org.bremersee.exception.servlet.ApiExceptionResolver;
24  import org.bremersee.exception.servlet.HttpServletRequestIdProvider;
25  import org.bremersee.exception.spring.boot.autoconfigure.RestApiExceptionMapperBootProperties;
26  import org.springframework.beans.factory.ObjectProvider;
27  import org.springframework.boot.autoconfigure.AutoConfiguration;
28  import org.springframework.boot.autoconfigure.AutoConfigureAfter;
29  import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
30  import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
31  import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
32  import org.springframework.boot.context.event.ApplicationReadyEvent;
33  import org.springframework.boot.context.properties.EnableConfigurationProperties;
34  import org.springframework.context.event.EventListener;
35  import org.springframework.util.Assert;
36  import org.springframework.util.ClassUtils;
37  import org.springframework.web.servlet.HandlerExceptionResolver;
38  import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
39  import tools.jackson.databind.json.JsonMapper;
40  import tools.jackson.dataformat.xml.XmlMapper;
41  
42  /**
43   * The api exception resolver autoconfiguration.
44   */
45  @ConditionalOnWebApplication(type = Type.SERVLET)
46  @ConditionalOnClass(name = {
47      "tools.jackson.databind.ObjectMapper",
48      "org.bremersee.exception.RestApiExceptionMapperProperties",
49      "org.bremersee.exception.servlet.ApiExceptionResolver"
50  })
51  @AutoConfigureAfter({
52      RestApiExceptionMapperForWebAutoConfiguration.class
53  })
54  @AutoConfiguration
55  @EnableConfigurationProperties({RestApiExceptionMapperBootProperties.class})
56  public class ApiExceptionResolverAutoConfiguration implements WebMvcConfigurer {
57  
58    private static final Log log = LogFactory
59        .getLog(ApiExceptionResolverAutoConfiguration.class);
60  
61    private final RestApiExceptionMapperBootProperties properties;
62  
63    private final ApiExceptionResolver apiExceptionResolver;
64  
65    /**
66     * Instantiates a new api exception resolver autoconfiguration.
67     *
68     * @param properties the properties
69     * @param apiExceptionMapper the api exception mapper
70     * @param jsonMapperBuilderProvider the json mapper builder provider
71     * @param xmlMapperBuilderProvider the xml mapper builder provider
72     * @param restApiIdProvider the rest api id provider
73     */
74    public ApiExceptionResolverAutoConfiguration(
75        RestApiExceptionMapperBootProperties properties,
76        ObjectProvider<RestApiExceptionMapper> apiExceptionMapper,
77        ObjectProvider<JsonMapper.Builder> jsonMapperBuilderProvider,
78        ObjectProvider<XmlMapper.Builder> xmlMapperBuilderProvider,
79        ObjectProvider<HttpServletRequestIdProvider> restApiIdProvider) {
80  
81      RestApiExceptionMapper mapper = apiExceptionMapper.getIfAvailable();
82      Assert.notNull(mapper, "Api exception resolver must be present.");
83      this.properties = properties;
84      this.apiExceptionResolver = new ApiExceptionResolver(
85          properties.getApiPaths(),
86          mapper,
87          jsonMapperBuilderProvider.getIfAvailable(),
88          xmlMapperBuilderProvider.getIfAvailable());
89      this.apiExceptionResolver.setRestApiExceptionIdProvider(restApiIdProvider.getIfAvailable());
90    }
91  
92    /**
93     * Init.
94     */
95    @EventListener(ApplicationReadyEvent.class)
96    public void init() {
97      log.info(String.format("""
98              
99              *********************************************************************************
100             * %s
101             *********************************************************************************
102             * apiPaths = %s
103             *********************************************************************************""",
104         ClassUtils.getUserClass(getClass()).getSimpleName(),
105         properties.getApiPaths()));
106   }
107 
108   @Override
109   public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
110     log.info(String.format("Adding exception resolver [%s] to registry.",
111         ClassUtils.getUserClass(apiExceptionResolver).getSimpleName()));
112     exceptionResolvers.addFirst(apiExceptionResolver);
113   }
114 
115 }