View Javadoc
1   /*
2    * Copyright 2022-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.spring.boot.autoconfigure.data.mongo;
18  
19  import java.util.Collection;
20  import java.util.Comparator;
21  import java.util.List;
22  import java.util.Objects;
23  import java.util.ServiceLoader;
24  import java.util.ServiceLoader.Provider;
25  import java.util.stream.Stream;
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  import org.bremersee.spring.boot.autoconfigure.data.mongo.MongoCustomConversionsFilter.DefaultFilter;
29  import org.bremersee.spring.data.mongodb.core.convert.MongoCustomConversionsProvider;
30  import org.springframework.boot.autoconfigure.AutoConfiguration;
31  import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
32  import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
33  import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
34  import org.springframework.boot.context.event.ApplicationReadyEvent;
35  import org.springframework.boot.context.properties.EnableConfigurationProperties;
36  import org.springframework.context.annotation.Bean;
37  import org.springframework.context.annotation.Primary;
38  import org.springframework.context.event.EventListener;
39  import org.springframework.core.convert.converter.Converter;
40  import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
41  import org.springframework.util.ClassUtils;
42  
43  /**
44   * The mongo custom conversions' autoconfiguration.
45   *
46   * @author Christian Bremer
47   */
48  @ConditionalOnProperty(
49      name = "bremersee.data.mongo.custom-conversions.enable",
50      havingValue = "true",
51      matchIfMissing = true)
52  @EnableConfigurationProperties(MongoProperties.class)
53  @ConditionalOnClass(name = {
54      "org.bremersee.spring.data.mongodb.core.convert.MongoCustomConversionsProvider",
55      "org.springframework.data.mongodb.core.convert.MongoCustomConversions"})
56  @AutoConfiguration
57  public class MongoCustomConversionsAutoConfiguration {
58  
59    private static final Log log = LogFactory.getLog(MongoCustomConversionsAutoConfiguration.class);
60  
61    private final MongoProperties.CustomConversionsProperties properties;
62  
63    /**
64     * Instantiates a new mongo custom conversions autoconfiguration.
65     *
66     * @param properties the properties
67     */
68    public MongoCustomConversionsAutoConfiguration(
69        MongoProperties properties) {
70      this.properties = properties.getCustomConversions();
71    }
72  
73    /**
74     * Init.
75     */
76    @EventListener(ApplicationReadyEvent.class)
77    public void init() {
78      log.info(String.format("""
79              
80              *********************************************************************************
81              * %s
82              *********************************************************************************
83              * properties = %s
84              *********************************************************************************""",
85          ClassUtils.getUserClass(getClass()).getSimpleName(), properties));
86    }
87  
88    /**
89     * Create mongo custom conversions filter bean.
90     *
91     * @return the mongo custom conversions filter
92     */
93    @ConditionalOnMissingBean
94    @Bean
95    public MongoCustomConversionsFilter mongoCustomConversionsFilter() {
96      return new DefaultFilter(
97          properties.isReadWriteAnnotationRequired(),
98          properties.getAllowClassNames());
99    }
100 
101   /**
102    * Create custom conversions bean.
103    *
104    * @param mongoCustomConversionsFilter the mongo custom conversions filter
105    * @param conversionsProviders the configurers
106    * @return the mongo custom conversions
107    */
108   @Primary
109   @Bean
110   public MongoCustomConversions customConversions(
111       MongoCustomConversionsFilter mongoCustomConversionsFilter,
112       List<MongoCustomConversionsProvider> conversionsProviders) {
113 
114     log.info("Adding mongo custom conversions ...");
115     List<Converter<?, ?>> converters = Stream
116         .concat(
117             conversionsProviders.stream(),
118             ServiceLoader.load(MongoCustomConversionsProvider.class).stream()
119                 .map(Provider::get))
120         .map(MongoCustomConversionsProvider::getCustomConversions)
121         .filter(Objects::nonNull)
122         .flatMap(Collection::stream)
123         .filter(Objects::nonNull)
124         .distinct()
125         .sorted(Comparator.comparing(c -> c.getClass().getName()))
126         .filter(mongoCustomConversionsFilter)
127         .toList();
128     return new MongoCustomConversions(converters);
129   }
130 
131 }