diff --git a/core/build.gradle b/core/build.gradle index 79474443..8d2c3ddf 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -16,6 +16,7 @@ dependencies { management platform(project(":spring-ldap-dependencies")) api "org.springframework:spring-core" api "org.springframework:spring-beans" + api "org.springframework:spring-context" api "org.springframework:spring-tx" api "io.micrometer:micrometer-core" diff --git a/core/src/main/java/org/springframework/ldap/convert/ConversionServiceBeanFactoryPostProcessor.java b/core/src/main/java/org/springframework/ldap/convert/ConversionServiceBeanFactoryPostProcessor.java new file mode 100644 index 00000000..96a196df --- /dev/null +++ b/core/src/main/java/org/springframework/ldap/convert/ConversionServiceBeanFactoryPostProcessor.java @@ -0,0 +1,63 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ldap.convert; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.converter.ConverterRegistry; + +/** + * A {@link BeanFactoryPostProcessor} to add Spring LDAP converters to the default + * {@link ConversionService}. + * + *

+ * Note that this post processor will ignore user-defined {@link ConversionService} beans + * named {@code conversionService}. + * + *

+ * In that case, you can apply {@link ConverterUtils#addDefaultConverters} to your + * instance instead + * + * @author Josh Cummings + * @since 3.3 + */ +public final class ConversionServiceBeanFactoryPostProcessor implements BeanFactoryPostProcessor { + + private static final String CONVERSION_SERVICE_BEAN_NAME = "conversionService"; + + /** + * {@inheritDoc} + */ + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + if (hasUserDefinedConversionService(beanFactory)) { + return; + } + ConversionService service = beanFactory.getConversionService(); + if (service instanceof ConverterRegistry registry) { + ConverterUtils.addDefaultConverters(registry); + } + } + + private boolean hasUserDefinedConversionService(ConfigurableListableBeanFactory beanFactory) { + return beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) + && beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class); + } + +} diff --git a/core/src/main/java/org/springframework/ldap/odm/config/ObjectDirectoryMapperConfiguration.java b/core/src/main/java/org/springframework/ldap/odm/config/ObjectDirectoryMapperConfiguration.java new file mode 100644 index 00000000..30a10a7e --- /dev/null +++ b/core/src/main/java/org/springframework/ldap/odm/config/ObjectDirectoryMapperConfiguration.java @@ -0,0 +1,49 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ldap.odm.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Fallback; +import org.springframework.core.convert.ConversionService; +import org.springframework.ldap.convert.ConversionServiceBeanFactoryPostProcessor; +import org.springframework.ldap.odm.core.ObjectDirectoryMapper; +import org.springframework.ldap.odm.core.impl.DefaultObjectDirectoryMapper; + +/** + * Configuration class for {@link ObjectDirectoryMapper} + * + * @author Josh Cummings + * @since 3.3 + */ +@Configuration(proxyBeanMethods = false) +public class ObjectDirectoryMapperConfiguration { + + @Bean + ConversionServiceBeanFactoryPostProcessor conversionServiceBeanPostProcessor() { + return new ConversionServiceBeanFactoryPostProcessor(); + } + + @Bean + @Fallback + ObjectDirectoryMapper objectDirectoryMapper(ConversionService conversionService) { + DefaultObjectDirectoryMapper objectDirectoryMapper = new DefaultObjectDirectoryMapper(); + objectDirectoryMapper.setConversionService(conversionService); + return objectDirectoryMapper; + } + +} diff --git a/modules/ROOT/pages/odm.adoc b/modules/ROOT/pages/odm.adoc index d11771cd..6131e887 100644 --- a/modules/ROOT/pages/odm.adoc +++ b/modules/ROOT/pages/odm.adoc @@ -14,6 +14,38 @@ The Spring LDAP project offers a similar ability with respect to LDAP directorie * `void update(Object entry)` * `void delete(Object entry)` +[[configuration]] +== Configuration + +`LdapTemplate` constructs a default `ObjectDirectoryMapper` which typically renders additional configuration unnecessary. + +However, you can also make `ObjectDirectoryMapper` available as a `@Bean` by importing `ObjectDirectoryMapperConfiguration` like so: + +[source,java] +---- +@Import(ObjectDirectoryMapperConfiguration.class) +@Configuration +public class LdapConfig { + // ... +} +---- + +You can then supply it to your `LdapTemplate` instance as follows: + +[source,java] +---- +@Bean +LdapTemplate ldapTemplate(ContextSource contextSource, ObjectDirectoryMapper odm) { + LdapTemplate ldap = new LdapTemplate(contextSource); + ldap.setObjectDirectoryMapper(odm); + return ldap; +} +---- + +Using this import provides the benefit that it will automatically configure `ObjectDirectoryMapper` with the `ConversionService` in the `ApplicationContext`. + +This means that Spring LDAP will use your configured `Converter` instances. + [[annotations]] == Annotations