parent
							
								
									df417bf317
								
							
						
					
					
						commit
						685d2d4391
					
				| 
						 | 
				
			
			@ -48,7 +48,6 @@ import org.springframework.boot.autoconfigure.jackson.JacksonProperties.Construc
 | 
			
		|||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
 | 
			
		||||
import org.springframework.boot.jackson.JsonComponentModule;
 | 
			
		||||
import org.springframework.boot.jackson.JsonMixinModule;
 | 
			
		||||
import org.springframework.boot.jackson.JsonMixinScanPackages;
 | 
			
		||||
import org.springframework.context.ApplicationContext;
 | 
			
		||||
import org.springframework.context.annotation.Bean;
 | 
			
		||||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
| 
						 | 
				
			
			@ -98,10 +97,8 @@ public class JacksonAutoConfiguration {
 | 
			
		|||
 | 
			
		||||
	@Bean
 | 
			
		||||
	public JsonMixinModule jsonMixinModule(ApplicationContext context) {
 | 
			
		||||
		List<String> packages = JsonMixinScanPackages.get(context).getPackageNames();
 | 
			
		||||
		if (packages.isEmpty() && AutoConfigurationPackages.has(context)) {
 | 
			
		||||
			packages = AutoConfigurationPackages.get(context);
 | 
			
		||||
		}
 | 
			
		||||
		List<String> packages = AutoConfigurationPackages.has(context) ? AutoConfigurationPackages.get(context)
 | 
			
		||||
				: Collections.emptyList();
 | 
			
		||||
		return new JsonMixinModule(context, packages);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -47,8 +47,10 @@ import com.fasterxml.jackson.databind.exc.InvalidFormatException;
 | 
			
		|||
import com.fasterxml.jackson.databind.module.SimpleModule;
 | 
			
		||||
import com.fasterxml.jackson.databind.util.StdDateFormat;
 | 
			
		||||
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
 | 
			
		||||
import org.assertj.core.api.InstanceOfAssertFactories;
 | 
			
		||||
import org.junit.jupiter.api.Test;
 | 
			
		||||
 | 
			
		||||
import org.springframework.boot.autoconfigure.AutoConfigurationPackage;
 | 
			
		||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
 | 
			
		||||
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
 | 
			
		||||
import org.springframework.boot.jackson.JsonComponent;
 | 
			
		||||
| 
						 | 
				
			
			@ -92,8 +94,13 @@ class JacksonAutoConfigurationTests {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void jsonMixinModuleShouldBeAutoconfigured() {
 | 
			
		||||
		this.contextRunner.run((context) -> assertThat(context).hasSingleBean(JsonMixinModule.class));
 | 
			
		||||
	void jsonMixinModuleShouldBeAutoConfiguredWithBasePackages() {
 | 
			
		||||
		this.contextRunner.withUserConfiguration(MixinConfiguration.class).run((context) -> {
 | 
			
		||||
			assertThat(context).hasSingleBean(JsonMixinModule.class);
 | 
			
		||||
			JsonMixinModule module = context.getBean(JsonMixinModule.class);
 | 
			
		||||
			assertThat(module).extracting("basePackages", InstanceOfAssertFactories.list(String.class))
 | 
			
		||||
					.containsExactly(MixinConfiguration.class.getPackage().getName());
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
| 
						 | 
				
			
			@ -637,4 +644,9 @@ class JacksonAutoConfigurationTests {
 | 
			
		|||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@AutoConfigurationPackage
 | 
			
		||||
	static class MixinConfiguration {
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,6 +40,14 @@ include::code:object/MyJsonComponent[]
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[[features.json.jackson.mixins]]
 | 
			
		||||
==== Mixins
 | 
			
		||||
Jackson has support for mixins that can be used to mix additional annotations into those already declared on a target class.
 | 
			
		||||
Spring Boot's Jackson auto-configuration will scan your application's packages for classes annotated with `@JsonMixin` and register them with the auto-configured `ObjectMapper`.
 | 
			
		||||
The registration is performed by Spring Boot's `JsonMixinModule`.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[[features.json.gson]]
 | 
			
		||||
=== Gson
 | 
			
		||||
Auto-configuration for Gson is provided.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,6 @@
 | 
			
		|||
 | 
			
		||||
package org.springframework.boot.jackson;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
 | 
			
		||||
import com.fasterxml.jackson.databind.Module;
 | 
			
		||||
| 
						 | 
				
			
			@ -29,15 +28,16 @@ import org.springframework.context.ApplicationContext;
 | 
			
		|||
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
 | 
			
		||||
import org.springframework.core.annotation.MergedAnnotation;
 | 
			
		||||
import org.springframework.core.annotation.MergedAnnotations;
 | 
			
		||||
import org.springframework.core.type.classreading.MetadataReader;
 | 
			
		||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
 | 
			
		||||
import org.springframework.util.Assert;
 | 
			
		||||
import org.springframework.util.ClassUtils;
 | 
			
		||||
import org.springframework.util.ObjectUtils;
 | 
			
		||||
import org.springframework.util.StringUtils;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Spring Bean and Jackson {@link Module} to register {@link JsonMixin @JsonMixin}
 | 
			
		||||
 * annotated beans.
 | 
			
		||||
 * Spring Bean and Jackson {@link Module} to find and
 | 
			
		||||
 * {@link SimpleModule#setMixInAnnotation(Class, Class) register}
 | 
			
		||||
 * {@link JsonMixin @JsonMixin}-annotated classes.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Guirong Hu
 | 
			
		||||
 * @since 2.7.0
 | 
			
		||||
| 
						 | 
				
			
			@ -68,7 +68,6 @@ public class JsonMixinModule extends SimpleModule implements InitializingBean {
 | 
			
		|||
		JsonMixinComponentScanner scanner = new JsonMixinComponentScanner();
 | 
			
		||||
		scanner.setEnvironment(this.context.getEnvironment());
 | 
			
		||||
		scanner.setResourceLoader(this.context);
 | 
			
		||||
 | 
			
		||||
		for (String basePackage : this.basePackages) {
 | 
			
		||||
			if (StringUtils.hasText(basePackage)) {
 | 
			
		||||
				for (BeanDefinition candidate : scanner.findCandidateComponents(basePackage)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -81,25 +80,20 @@ public class JsonMixinModule extends SimpleModule implements InitializingBean {
 | 
			
		|||
	private void addJsonMixin(Class<?> mixinClass) {
 | 
			
		||||
		MergedAnnotation<JsonMixin> annotation = MergedAnnotations
 | 
			
		||||
				.from(mixinClass, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY).get(JsonMixin.class);
 | 
			
		||||
		Class<?>[] targetTypes = annotation.getClassArray("type");
 | 
			
		||||
		if (ObjectUtils.isEmpty(targetTypes)) {
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		for (Class<?> targetType : targetTypes) {
 | 
			
		||||
		for (Class<?> targetType : annotation.getClassArray("type")) {
 | 
			
		||||
			setMixInAnnotation(targetType, mixinClass);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static class JsonMixinComponentScanner extends ClassPathScanningCandidateComponentProvider {
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
 | 
			
		||||
			return true;
 | 
			
		||||
		JsonMixinComponentScanner() {
 | 
			
		||||
			addIncludeFilter(new AnnotationTypeFilter(JsonMixin.class));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
 | 
			
		||||
			return beanDefinition.getMetadata().hasAnnotation(JsonMixin.class.getName());
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,75 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright 2012-2022 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.boot.jackson;
 | 
			
		||||
 | 
			
		||||
import java.lang.annotation.Documented;
 | 
			
		||||
import java.lang.annotation.ElementType;
 | 
			
		||||
import java.lang.annotation.Retention;
 | 
			
		||||
import java.lang.annotation.RetentionPolicy;
 | 
			
		||||
import java.lang.annotation.Target;
 | 
			
		||||
 | 
			
		||||
import org.springframework.context.annotation.Import;
 | 
			
		||||
import org.springframework.core.annotation.AliasFor;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Configures the base packages used by auto-configuration when scanning for mix-in
 | 
			
		||||
 * classes. One of {@link #basePackageClasses()}, {@link #basePackages()} or its alias
 | 
			
		||||
 * {@link #value()} may be specified to define specific packages to scan. If specific
 | 
			
		||||
 * packages are not defined scanning will occur from the package of the class with this
 | 
			
		||||
 * annotation.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Guirong Hu
 | 
			
		||||
 * @since 2.7.0
 | 
			
		||||
 * @see JsonMixinScanPackages
 | 
			
		||||
 */
 | 
			
		||||
@Target(ElementType.TYPE)
 | 
			
		||||
@Retention(RetentionPolicy.RUNTIME)
 | 
			
		||||
@Documented
 | 
			
		||||
@Import(JsonMixinScanPackages.Registrar.class)
 | 
			
		||||
public @interface JsonMixinScan {
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Alias for the {@link #basePackages()} attribute. Allows for more concise annotation
 | 
			
		||||
	 * declarations e.g.: {@code @JsonMixinScan("org.my.pkg")} instead of
 | 
			
		||||
	 * {@code @JsonMixinScan(basePackages="org.my.pkg")}.
 | 
			
		||||
	 * @return the base packages to scan
 | 
			
		||||
	 */
 | 
			
		||||
	@AliasFor("basePackages")
 | 
			
		||||
	String[] value() default {};
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Base packages to scan for mix-in classes. {@link #value()} is an alias for (and
 | 
			
		||||
	 * mutually exclusive with) this attribute.
 | 
			
		||||
	 * <p>
 | 
			
		||||
	 * Use {@link #basePackageClasses()} for a type-safe alternative to String-based
 | 
			
		||||
	 * package names.
 | 
			
		||||
	 * @return the base packages to scan
 | 
			
		||||
	 */
 | 
			
		||||
	@AliasFor("value")
 | 
			
		||||
	String[] basePackages() default {};
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Type-safe alternative to {@link #basePackages()} for specifying the packages to
 | 
			
		||||
	 * scan for mix-in classes. The package of each class specified will be scanned.
 | 
			
		||||
	 * <p>
 | 
			
		||||
	 * Consider creating a special no-op marker class or interface in each package that
 | 
			
		||||
	 * serves no purpose other than being referenced by this attribute.
 | 
			
		||||
	 * @return classes from the base packages to scan
 | 
			
		||||
	 */
 | 
			
		||||
	Class<?>[] basePackageClasses() default {};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,185 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright 2012-2022 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.boot.jackson;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.LinkedHashSet;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import java.util.function.Supplier;
 | 
			
		||||
 | 
			
		||||
import org.springframework.beans.factory.BeanFactory;
 | 
			
		||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
 | 
			
		||||
import org.springframework.beans.factory.config.BeanDefinition;
 | 
			
		||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
 | 
			
		||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
 | 
			
		||||
import org.springframework.context.ConfigurableApplicationContext;
 | 
			
		||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
 | 
			
		||||
import org.springframework.core.annotation.AnnotationAttributes;
 | 
			
		||||
import org.springframework.core.env.Environment;
 | 
			
		||||
import org.springframework.core.type.AnnotationMetadata;
 | 
			
		||||
import org.springframework.util.Assert;
 | 
			
		||||
import org.springframework.util.ClassUtils;
 | 
			
		||||
import org.springframework.util.StringUtils;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class for storing {@link JsonMixinScan @JsonMixinScan} specified packages for reference
 | 
			
		||||
 * later.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Guirong Hu
 | 
			
		||||
 * @since 2.7.0
 | 
			
		||||
 * @see JsonMixinScan
 | 
			
		||||
 * @see JsonMixinModule
 | 
			
		||||
 */
 | 
			
		||||
public class JsonMixinScanPackages {
 | 
			
		||||
 | 
			
		||||
	private static final String BEAN = JsonMixinScanPackages.class.getName();
 | 
			
		||||
 | 
			
		||||
	private static final JsonMixinScanPackages NONE = new JsonMixinScanPackages();
 | 
			
		||||
 | 
			
		||||
	private final List<String> packageNames;
 | 
			
		||||
 | 
			
		||||
	JsonMixinScanPackages(String... packageNames) {
 | 
			
		||||
		List<String> packages = new ArrayList<>();
 | 
			
		||||
		for (String name : packageNames) {
 | 
			
		||||
			if (StringUtils.hasText(name)) {
 | 
			
		||||
				packages.add(name);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		this.packageNames = Collections.unmodifiableList(packages);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Return the package names specified from all {@link JsonMixinScan @JsonMixinScan}
 | 
			
		||||
	 * annotations.
 | 
			
		||||
	 * @return the mix-in classes scan package names
 | 
			
		||||
	 */
 | 
			
		||||
	public List<String> getPackageNames() {
 | 
			
		||||
		return this.packageNames;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Return the {@link JsonMixinScanPackages} for the given bean factory.
 | 
			
		||||
	 * @param beanFactory the source bean factory
 | 
			
		||||
	 * @return the {@link JsonMixinScanPackages} for the bean factory (never {@code null})
 | 
			
		||||
	 */
 | 
			
		||||
	public static JsonMixinScanPackages get(BeanFactory beanFactory) {
 | 
			
		||||
		// Currently, we only store a single base package, but we return a list to
 | 
			
		||||
		// allow this to change in the future if needed
 | 
			
		||||
		try {
 | 
			
		||||
			return beanFactory.getBean(BEAN, JsonMixinScanPackages.class);
 | 
			
		||||
		}
 | 
			
		||||
		catch (NoSuchBeanDefinitionException ex) {
 | 
			
		||||
			return NONE;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Register the specified mix-in classes scan packages with the system.
 | 
			
		||||
	 * @param registry the source registry
 | 
			
		||||
	 * @param packageNames the package names to register
 | 
			
		||||
	 */
 | 
			
		||||
	public static void register(BeanDefinitionRegistry registry, String... packageNames) {
 | 
			
		||||
		Assert.notNull(registry, "Registry must not be null");
 | 
			
		||||
		Assert.notNull(packageNames, "PackageNames must not be null");
 | 
			
		||||
		register(registry, Arrays.asList(packageNames));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Register the specified mix-in classes scan packages with the system.
 | 
			
		||||
	 * @param registry the source registry
 | 
			
		||||
	 * @param packageNames the package names to register
 | 
			
		||||
	 */
 | 
			
		||||
	public static void register(BeanDefinitionRegistry registry, Collection<String> packageNames) {
 | 
			
		||||
		Assert.notNull(registry, "Registry must not be null");
 | 
			
		||||
		Assert.notNull(packageNames, "PackageNames must not be null");
 | 
			
		||||
		if (registry.containsBeanDefinition(BEAN)) {
 | 
			
		||||
			JsonMixinScanPackagesBeanDefinition beanDefinition = (JsonMixinScanPackagesBeanDefinition) registry
 | 
			
		||||
					.getBeanDefinition(BEAN);
 | 
			
		||||
			beanDefinition.addPackageNames(packageNames);
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			registry.registerBeanDefinition(BEAN, new JsonMixinScanPackagesBeanDefinition(packageNames));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * {@link ImportBeanDefinitionRegistrar} to store the base package from the importing
 | 
			
		||||
	 * configuration.
 | 
			
		||||
	 */
 | 
			
		||||
	static class Registrar implements ImportBeanDefinitionRegistrar {
 | 
			
		||||
 | 
			
		||||
		private final Environment environment;
 | 
			
		||||
 | 
			
		||||
		Registrar(Environment environment) {
 | 
			
		||||
			this.environment = environment;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
 | 
			
		||||
			register(registry, getPackagesToScan(metadata));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private Set<String> getPackagesToScan(AnnotationMetadata metadata) {
 | 
			
		||||
			AnnotationAttributes attributes = AnnotationAttributes
 | 
			
		||||
					.fromMap(metadata.getAnnotationAttributes(JsonMixinScan.class.getName()));
 | 
			
		||||
			Set<String> packagesToScan = new LinkedHashSet<>();
 | 
			
		||||
			for (String basePackage : attributes.getStringArray("basePackages")) {
 | 
			
		||||
				String[] tokenized = StringUtils.tokenizeToStringArray(
 | 
			
		||||
						this.environment.resolvePlaceholders(basePackage),
 | 
			
		||||
						ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
 | 
			
		||||
				Collections.addAll(packagesToScan, tokenized);
 | 
			
		||||
			}
 | 
			
		||||
			for (Class<?> basePackageClass : attributes.getClassArray("basePackageClasses")) {
 | 
			
		||||
				packagesToScan.add(this.environment.resolvePlaceholders(ClassUtils.getPackageName(basePackageClass)));
 | 
			
		||||
			}
 | 
			
		||||
			if (packagesToScan.isEmpty()) {
 | 
			
		||||
				String packageName = ClassUtils.getPackageName(metadata.getClassName());
 | 
			
		||||
				Assert.state(StringUtils.hasLength(packageName),
 | 
			
		||||
						"@JsonMixinScan cannot be used with the default package");
 | 
			
		||||
				return Collections.singleton(packageName);
 | 
			
		||||
			}
 | 
			
		||||
			return packagesToScan;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static class JsonMixinScanPackagesBeanDefinition extends GenericBeanDefinition {
 | 
			
		||||
 | 
			
		||||
		private final Set<String> packageNames = new LinkedHashSet<>();
 | 
			
		||||
 | 
			
		||||
		JsonMixinScanPackagesBeanDefinition(Collection<String> packageNames) {
 | 
			
		||||
			setBeanClass(JsonMixinScanPackages.class);
 | 
			
		||||
			setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
 | 
			
		||||
			addPackageNames(packageNames);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		public Supplier<?> getInstanceSupplier() {
 | 
			
		||||
			return () -> new JsonMixinScanPackages(StringUtils.toStringArray(this.packageNames));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void addPackageNames(Collection<String> additionalPackageNames) {
 | 
			
		||||
			this.packageNames.addAll(additionalPackageNames);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -41,7 +41,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
 | 
			
		|||
 *
 | 
			
		||||
 * @author Guirong Hu
 | 
			
		||||
 */
 | 
			
		||||
public class JsonMixinModuleTests {
 | 
			
		||||
class JsonMixinModuleTests {
 | 
			
		||||
 | 
			
		||||
	private AnnotationConfigApplicationContext context;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,182 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright 2012-2022 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.boot.jackson;
 | 
			
		||||
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
 | 
			
		||||
import org.junit.jupiter.api.AfterEach;
 | 
			
		||||
import org.junit.jupiter.api.Test;
 | 
			
		||||
 | 
			
		||||
import org.springframework.beans.factory.support.RootBeanDefinition;
 | 
			
		||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 | 
			
		||||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
import org.springframework.core.annotation.AnnotationConfigurationException;
 | 
			
		||||
 | 
			
		||||
import static org.assertj.core.api.Assertions.assertThat;
 | 
			
		||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
 | 
			
		||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests for {@link JsonMixinScanPackages}.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Guirong Hu
 | 
			
		||||
 */
 | 
			
		||||
class JsonMixinScanPackagesTests {
 | 
			
		||||
 | 
			
		||||
	private AnnotationConfigApplicationContext context;
 | 
			
		||||
 | 
			
		||||
	@AfterEach
 | 
			
		||||
	void cleanup() {
 | 
			
		||||
		if (this.context != null) {
 | 
			
		||||
			this.context.close();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void getWhenNoneRegisteredShouldReturnNone() {
 | 
			
		||||
		this.context = new AnnotationConfigApplicationContext();
 | 
			
		||||
		this.context.refresh();
 | 
			
		||||
		JsonMixinScanPackages packages = JsonMixinScanPackages.get(this.context);
 | 
			
		||||
		assertThat(packages).isNotNull();
 | 
			
		||||
		assertThat(packages.getPackageNames()).isEmpty();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void getShouldReturnRegisterPackages() {
 | 
			
		||||
		this.context = new AnnotationConfigApplicationContext();
 | 
			
		||||
		JsonMixinScanPackages.register(this.context, "a", "b");
 | 
			
		||||
		JsonMixinScanPackages.register(this.context, "b", "c");
 | 
			
		||||
		this.context.refresh();
 | 
			
		||||
		JsonMixinScanPackages packages = JsonMixinScanPackages.get(this.context);
 | 
			
		||||
		assertThat(packages.getPackageNames()).containsExactly("a", "b", "c");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void registerFromArrayWhenRegistryIsNullShouldThrowException() {
 | 
			
		||||
		assertThatIllegalArgumentException().isThrownBy(() -> JsonMixinScanPackages.register(null))
 | 
			
		||||
				.withMessageContaining("Registry must not be null");
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void registerFromArrayWhenPackageNamesIsNullShouldThrowException() {
 | 
			
		||||
		this.context = new AnnotationConfigApplicationContext();
 | 
			
		||||
		assertThatIllegalArgumentException()
 | 
			
		||||
				.isThrownBy(() -> JsonMixinScanPackages.register(this.context, (String[]) null))
 | 
			
		||||
				.withMessageContaining("PackageNames must not be null");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void registerFromCollectionWhenRegistryIsNullShouldThrowException() {
 | 
			
		||||
		assertThatIllegalArgumentException()
 | 
			
		||||
				.isThrownBy(() -> JsonMixinScanPackages.register(null, Collections.emptyList()))
 | 
			
		||||
				.withMessageContaining("Registry must not be null");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void registerFromCollectionWhenPackageNamesIsNullShouldThrowException() {
 | 
			
		||||
		this.context = new AnnotationConfigApplicationContext();
 | 
			
		||||
		assertThatIllegalArgumentException()
 | 
			
		||||
				.isThrownBy(() -> JsonMixinScanPackages.register(this.context, (Collection<String>) null))
 | 
			
		||||
				.withMessageContaining("PackageNames must not be null");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void jsonMixinScanAnnotationWhenHasValueAttributeShouldSetupPackages() {
 | 
			
		||||
		this.context = new AnnotationConfigApplicationContext(JsonMixinScanValueConfig.class);
 | 
			
		||||
		JsonMixinScanPackages packages = JsonMixinScanPackages.get(this.context);
 | 
			
		||||
		assertThat(packages.getPackageNames()).containsExactly("a");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void jsonMixinScanAnnotationWhenHasValueAttributeShouldSetupPackagesAsm() {
 | 
			
		||||
		this.context = new AnnotationConfigApplicationContext();
 | 
			
		||||
		this.context.registerBeanDefinition("jsonMixinScanValueConfig",
 | 
			
		||||
				new RootBeanDefinition(JsonMixinScanValueConfig.class.getName()));
 | 
			
		||||
		this.context.refresh();
 | 
			
		||||
		JsonMixinScanPackages packages = JsonMixinScanPackages.get(this.context);
 | 
			
		||||
		assertThat(packages.getPackageNames()).containsExactly("a");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void jsonMixinScanAnnotationWhenHasBasePackagesAttributeShouldSetupPackages() {
 | 
			
		||||
		this.context = new AnnotationConfigApplicationContext(JsonMixinScanBasePackagesConfig.class);
 | 
			
		||||
		JsonMixinScanPackages packages = JsonMixinScanPackages.get(this.context);
 | 
			
		||||
		assertThat(packages.getPackageNames()).containsExactly("b");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void jsonMixinScanAnnotationWhenHasValueAndBasePackagesAttributeShouldThrow() {
 | 
			
		||||
		assertThatExceptionOfType(AnnotationConfigurationException.class)
 | 
			
		||||
				.isThrownBy(() -> this.context = new AnnotationConfigApplicationContext(
 | 
			
		||||
						JsonMixinScanValueAndBasePackagesConfig.class));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void jsonMixinScanAnnotationWhenHasBasePackageClassesAttributeShouldSetupPackages() {
 | 
			
		||||
		this.context = new AnnotationConfigApplicationContext(JsonMixinScanBasePackageClassesConfig.class);
 | 
			
		||||
		JsonMixinScanPackages packages = JsonMixinScanPackages.get(this.context);
 | 
			
		||||
		assertThat(packages.getPackageNames()).containsExactly(getClass().getPackage().getName());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void jsonMixinScanAnnotationWhenNoAttributesShouldSetupPackages() {
 | 
			
		||||
		this.context = new AnnotationConfigApplicationContext(JsonMixinScanNoAttributesConfig.class);
 | 
			
		||||
		JsonMixinScanPackages packages = JsonMixinScanPackages.get(this.context);
 | 
			
		||||
		assertThat(packages.getPackageNames()).containsExactly(getClass().getPackage().getName());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void jsonMixinScanAnnotationWhenLoadingFromMultipleConfigsShouldCombinePackages() {
 | 
			
		||||
		this.context = new AnnotationConfigApplicationContext(JsonMixinScanValueConfig.class,
 | 
			
		||||
				JsonMixinScanBasePackagesConfig.class);
 | 
			
		||||
		JsonMixinScanPackages packages = JsonMixinScanPackages.get(this.context);
 | 
			
		||||
		assertThat(packages.getPackageNames()).containsExactly("a", "b");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Configuration(proxyBeanMethods = false)
 | 
			
		||||
	@JsonMixinScan("a")
 | 
			
		||||
	static class JsonMixinScanValueConfig {
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Configuration(proxyBeanMethods = false)
 | 
			
		||||
	@JsonMixinScan(basePackages = "b")
 | 
			
		||||
	static class JsonMixinScanBasePackagesConfig {
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Configuration(proxyBeanMethods = false)
 | 
			
		||||
	@JsonMixinScan(value = "a", basePackages = "b")
 | 
			
		||||
	static class JsonMixinScanValueAndBasePackagesConfig {
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Configuration(proxyBeanMethods = false)
 | 
			
		||||
	@JsonMixinScan(basePackageClasses = JsonMixinScanPackagesTests.class)
 | 
			
		||||
	static class JsonMixinScanBasePackageClassesConfig {
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Configuration(proxyBeanMethods = false)
 | 
			
		||||
	@JsonMixinScan
 | 
			
		||||
	static class JsonMixinScanNoAttributesConfig {
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue