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.context.properties.EnableConfigurationProperties; | ||||||
| import org.springframework.boot.jackson.JsonComponentModule; | import org.springframework.boot.jackson.JsonComponentModule; | ||||||
| import org.springframework.boot.jackson.JsonMixinModule; | import org.springframework.boot.jackson.JsonMixinModule; | ||||||
| import org.springframework.boot.jackson.JsonMixinScanPackages; |  | ||||||
| import org.springframework.context.ApplicationContext; | import org.springframework.context.ApplicationContext; | ||||||
| import org.springframework.context.annotation.Bean; | import org.springframework.context.annotation.Bean; | ||||||
| import org.springframework.context.annotation.Configuration; | import org.springframework.context.annotation.Configuration; | ||||||
|  | @ -98,10 +97,8 @@ public class JacksonAutoConfiguration { | ||||||
| 
 | 
 | ||||||
| 	@Bean | 	@Bean | ||||||
| 	public JsonMixinModule jsonMixinModule(ApplicationContext context) { | 	public JsonMixinModule jsonMixinModule(ApplicationContext context) { | ||||||
| 		List<String> packages = JsonMixinScanPackages.get(context).getPackageNames(); | 		List<String> packages = AutoConfigurationPackages.has(context) ? AutoConfigurationPackages.get(context) | ||||||
| 		if (packages.isEmpty() && AutoConfigurationPackages.has(context)) { | 				: Collections.emptyList(); | ||||||
| 			packages = AutoConfigurationPackages.get(context); |  | ||||||
| 		} |  | ||||||
| 		return new JsonMixinModule(context, packages); | 		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.module.SimpleModule; | ||||||
| import com.fasterxml.jackson.databind.util.StdDateFormat; | import com.fasterxml.jackson.databind.util.StdDateFormat; | ||||||
| import com.fasterxml.jackson.module.paramnames.ParameterNamesModule; | import com.fasterxml.jackson.module.paramnames.ParameterNamesModule; | ||||||
|  | import org.assertj.core.api.InstanceOfAssertFactories; | ||||||
| import org.junit.jupiter.api.Test; | import org.junit.jupiter.api.Test; | ||||||
| 
 | 
 | ||||||
|  | import org.springframework.boot.autoconfigure.AutoConfigurationPackage; | ||||||
| import org.springframework.boot.autoconfigure.AutoConfigurations; | import org.springframework.boot.autoconfigure.AutoConfigurations; | ||||||
| import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration; | import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration; | ||||||
| import org.springframework.boot.jackson.JsonComponent; | import org.springframework.boot.jackson.JsonComponent; | ||||||
|  | @ -92,8 +94,13 @@ class JacksonAutoConfigurationTests { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Test | 	@Test | ||||||
| 	void jsonMixinModuleShouldBeAutoconfigured() { | 	void jsonMixinModuleShouldBeAutoConfiguredWithBasePackages() { | ||||||
| 		this.contextRunner.run((context) -> assertThat(context).hasSingleBean(JsonMixinModule.class)); | 		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 | 	@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]] | [[features.json.gson]] | ||||||
| === Gson | === Gson | ||||||
| Auto-configuration for Gson is provided. | Auto-configuration for Gson is provided. | ||||||
|  |  | ||||||
|  | @ -16,7 +16,6 @@ | ||||||
| 
 | 
 | ||||||
| package org.springframework.boot.jackson; | package org.springframework.boot.jackson; | ||||||
| 
 | 
 | ||||||
| import java.io.IOException; |  | ||||||
| import java.util.Collection; | import java.util.Collection; | ||||||
| 
 | 
 | ||||||
| import com.fasterxml.jackson.databind.Module; | import com.fasterxml.jackson.databind.Module; | ||||||
|  | @ -29,15 +28,16 @@ import org.springframework.context.ApplicationContext; | ||||||
| import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; | import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; | ||||||
| import org.springframework.core.annotation.MergedAnnotation; | import org.springframework.core.annotation.MergedAnnotation; | ||||||
| import org.springframework.core.annotation.MergedAnnotations; | 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.Assert; | ||||||
| import org.springframework.util.ClassUtils; | import org.springframework.util.ClassUtils; | ||||||
| import org.springframework.util.ObjectUtils; | import org.springframework.util.ObjectUtils; | ||||||
| import org.springframework.util.StringUtils; | import org.springframework.util.StringUtils; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Spring Bean and Jackson {@link Module} to register {@link JsonMixin @JsonMixin} |  * Spring Bean and Jackson {@link Module} to find and | ||||||
|  * annotated beans. |  * {@link SimpleModule#setMixInAnnotation(Class, Class) register} | ||||||
|  |  * {@link JsonMixin @JsonMixin}-annotated classes. | ||||||
|  * |  * | ||||||
|  * @author Guirong Hu |  * @author Guirong Hu | ||||||
|  * @since 2.7.0 |  * @since 2.7.0 | ||||||
|  | @ -68,7 +68,6 @@ public class JsonMixinModule extends SimpleModule implements InitializingBean { | ||||||
| 		JsonMixinComponentScanner scanner = new JsonMixinComponentScanner(); | 		JsonMixinComponentScanner scanner = new JsonMixinComponentScanner(); | ||||||
| 		scanner.setEnvironment(this.context.getEnvironment()); | 		scanner.setEnvironment(this.context.getEnvironment()); | ||||||
| 		scanner.setResourceLoader(this.context); | 		scanner.setResourceLoader(this.context); | ||||||
| 
 |  | ||||||
| 		for (String basePackage : this.basePackages) { | 		for (String basePackage : this.basePackages) { | ||||||
| 			if (StringUtils.hasText(basePackage)) { | 			if (StringUtils.hasText(basePackage)) { | ||||||
| 				for (BeanDefinition candidate : scanner.findCandidateComponents(basePackage)) { | 				for (BeanDefinition candidate : scanner.findCandidateComponents(basePackage)) { | ||||||
|  | @ -81,25 +80,20 @@ public class JsonMixinModule extends SimpleModule implements InitializingBean { | ||||||
| 	private void addJsonMixin(Class<?> mixinClass) { | 	private void addJsonMixin(Class<?> mixinClass) { | ||||||
| 		MergedAnnotation<JsonMixin> annotation = MergedAnnotations | 		MergedAnnotation<JsonMixin> annotation = MergedAnnotations | ||||||
| 				.from(mixinClass, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY).get(JsonMixin.class); | 				.from(mixinClass, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY).get(JsonMixin.class); | ||||||
| 		Class<?>[] targetTypes = annotation.getClassArray("type"); | 		for (Class<?> targetType : annotation.getClassArray("type")) { | ||||||
| 		if (ObjectUtils.isEmpty(targetTypes)) { |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
| 		for (Class<?> targetType : targetTypes) { |  | ||||||
| 			setMixInAnnotation(targetType, mixinClass); | 			setMixInAnnotation(targetType, mixinClass); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	static class JsonMixinComponentScanner extends ClassPathScanningCandidateComponentProvider { | 	static class JsonMixinComponentScanner extends ClassPathScanningCandidateComponentProvider { | ||||||
| 
 | 
 | ||||||
| 		@Override | 		JsonMixinComponentScanner() { | ||||||
| 		protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException { | 			addIncludeFilter(new AnnotationTypeFilter(JsonMixin.class)); | ||||||
| 			return true; |  | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		@Override | 		@Override | ||||||
| 		protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) { | 		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 |  * @author Guirong Hu | ||||||
|  */ |  */ | ||||||
| public class JsonMixinModuleTests { | class JsonMixinModuleTests { | ||||||
| 
 | 
 | ||||||
| 	private AnnotationConfigApplicationContext context; | 	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