diff --git a/spring-test/src/main/java/org/springframework/test/context/support/AbstractDelegatingSmartContextLoader.java b/spring-test/src/main/java/org/springframework/test/context/support/AbstractDelegatingSmartContextLoader.java
index cee38772327..5687313a1e4 100644
--- a/spring-test/src/main/java/org/springframework/test/context/support/AbstractDelegatingSmartContextLoader.java
+++ b/spring-test/src/main/java/org/springframework/test/context/support/AbstractDelegatingSmartContextLoader.java
@@ -16,9 +16,6 @@
package org.springframework.test.context.support;
-import java.util.Arrays;
-import java.util.List;
-
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -88,33 +85,36 @@ public abstract class AbstractDelegatingSmartContextLoader implements SmartConte
protected abstract SmartContextLoader getAnnotationConfigLoader();
- // SmartContextLoader
+ // ContextLoader
- private static void delegateProcessing(SmartContextLoader loader, ContextConfigurationAttributes configAttributes) {
- if (logger.isDebugEnabled()) {
- logger.debug(String.format("Delegating to %s to process context configuration %s.",
- name(loader), configAttributes));
- }
- loader.processContextConfiguration(configAttributes);
+ /**
+ * {@code AbstractDelegatingSmartContextLoader} does not support the
+ * {@link ContextLoader#processLocations(Class, String...)} method. Call
+ * {@link #processContextConfiguration(ContextConfigurationAttributes)} instead.
+ * @throws UnsupportedOperationException in this implementation
+ */
+ @Override
+ public final String[] processLocations(Class> clazz, @Nullable String... locations) {
+ throw new UnsupportedOperationException(
+ "DelegatingSmartContextLoaders do not support the ContextLoader SPI. " +
+ "Call processContextConfiguration(ContextConfigurationAttributes) instead.");
}
- private static ApplicationContext delegateLoading(SmartContextLoader loader, MergedContextConfiguration mergedConfig)
- throws Exception {
-
- if (logger.isDebugEnabled()) {
- logger.debug(String.format("Delegating to %s to load context from %s.", name(loader), mergedConfig));
- }
- return loader.loadContext(mergedConfig);
+ /**
+ * {@code AbstractDelegatingSmartContextLoader} does not support the
+ * {@link ContextLoader#loadContext(String...) } method. Call
+ * {@link #loadContext(MergedContextConfiguration)} instead.
+ * @throws UnsupportedOperationException in this implementation
+ */
+ @Override
+ public final ApplicationContext loadContext(String... locations) throws Exception {
+ throw new UnsupportedOperationException(
+ "DelegatingSmartContextLoaders do not support the ContextLoader SPI. " +
+ "Call loadContext(MergedContextConfiguration) instead.");
}
- private boolean supports(SmartContextLoader loader, MergedContextConfiguration mergedConfig) {
- if (loader == getAnnotationConfigLoader()) {
- return (mergedConfig.hasClasses() && !mergedConfig.hasLocations());
- }
- else {
- return (mergedConfig.hasLocations() && !mergedConfig.hasClasses());
- }
- }
+
+ // SmartContextLoader
/**
* Delegates to candidate {@code SmartContextLoaders} to process the supplied
@@ -228,7 +228,7 @@ public abstract class AbstractDelegatingSmartContextLoader implements SmartConte
*/
@Override
public ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception {
- Assert.notNull(mergedConfig, "mergedConfig must not be null");
+ Assert.notNull(mergedConfig, "MergedContextConfiguration must not be null");
Assert.state(!(mergedConfig.hasLocations() && mergedConfig.hasClasses()), () -> String.format(
"Neither %s nor %s supports loading an ApplicationContext from %s: " +
@@ -236,7 +236,6 @@ public abstract class AbstractDelegatingSmartContextLoader implements SmartConte
name(getAnnotationConfigLoader()), mergedConfig));
SmartContextLoader[] candidates = {getXmlLoader(), getAnnotationConfigLoader()};
-
for (SmartContextLoader loader : candidates) {
// Determine if each loader can load a context from the mergedConfig. If it
// can, let it; otherwise, keep iterating.
@@ -254,41 +253,39 @@ public abstract class AbstractDelegatingSmartContextLoader implements SmartConte
// else...
throw new IllegalStateException(String.format(
- "Neither %s nor %s was able to load an ApplicationContext from %s.", name(getXmlLoader()),
- name(getAnnotationConfigLoader()), mergedConfig));
+ "Neither %s nor %s was able to load an ApplicationContext from %s.",
+ name(getXmlLoader()), name(getAnnotationConfigLoader()), mergedConfig));
}
- private static String name(SmartContextLoader loader) {
- return loader.getClass().getSimpleName();
+
+ private static void delegateProcessing(SmartContextLoader loader, ContextConfigurationAttributes configAttributes) {
+ if (logger.isDebugEnabled()) {
+ logger.debug(String.format("Delegating to %s to process context configuration %s.",
+ name(loader), configAttributes));
+ }
+ loader.processContextConfiguration(configAttributes);
}
+ private static ApplicationContext delegateLoading(SmartContextLoader loader, MergedContextConfiguration mergedConfig)
+ throws Exception {
- // ContextLoader
+ if (logger.isDebugEnabled()) {
+ logger.debug(String.format("Delegating to %s to load context from %s.", name(loader), mergedConfig));
+ }
+ return loader.loadContext(mergedConfig);
+ }
- /**
- * {@code AbstractDelegatingSmartContextLoader} does not support the
- * {@link ContextLoader#processLocations(Class, String...)} method. Call
- * {@link #processContextConfiguration(ContextConfigurationAttributes)} instead.
- * @throws UnsupportedOperationException in this implementation
- */
- @Override
- public final String[] processLocations(Class> clazz, @Nullable String... locations) {
- throw new UnsupportedOperationException(
- "DelegatingSmartContextLoaders do not support the ContextLoader SPI. " +
- "Call processContextConfiguration(ContextConfigurationAttributes) instead.");
+ private boolean supports(SmartContextLoader loader, MergedContextConfiguration mergedConfig) {
+ if (loader == getAnnotationConfigLoader()) {
+ return (mergedConfig.hasClasses() && !mergedConfig.hasLocations());
+ }
+ else {
+ return (mergedConfig.hasLocations() && !mergedConfig.hasClasses());
+ }
}
- /**
- * {@code AbstractDelegatingSmartContextLoader} does not support the
- * {@link ContextLoader#loadContext(String...) } method. Call
- * {@link #loadContext(MergedContextConfiguration)} instead.
- * @throws UnsupportedOperationException in this implementation
- */
- @Override
- public final ApplicationContext loadContext(String... locations) throws Exception {
- throw new UnsupportedOperationException(
- "DelegatingSmartContextLoaders do not support the ContextLoader SPI. " +
- "Call loadContext(MergedContextConfiguration) instead.");
+ private static String name(SmartContextLoader loader) {
+ return loader.getClass().getSimpleName();
}
}
diff --git a/spring-web/src/main/java/org/springframework/web/method/annotation/InitBinderDataBinderFactory.java b/spring-web/src/main/java/org/springframework/web/method/annotation/InitBinderDataBinderFactory.java
index eff95e42688..f6085d95aa6 100644
--- a/spring-web/src/main/java/org/springframework/web/method/annotation/InitBinderDataBinderFactory.java
+++ b/spring-web/src/main/java/org/springframework/web/method/annotation/InitBinderDataBinderFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2017 the original author or authors.
+ * Copyright 2002-2018 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.
@@ -16,8 +16,6 @@
package org.springframework.web.method.annotation;
-import java.util.Arrays;
-import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -57,15 +55,15 @@ public class InitBinderDataBinderFactory extends DefaultDataBinderFactory {
/**
* Initialize a WebDataBinder with {@code @InitBinder} methods.
- * If the {@code @InitBinder} annotation specifies attributes names, it is
- * invoked only if the names include the target object name.
+ *
If the {@code @InitBinder} annotation specifies attributes names,
+ * it is invoked only if the names include the target object name.
* @throws Exception if one of the invoked @{@link InitBinder} methods fail.
*/
@Override
- public void initBinder(WebDataBinder binder, NativeWebRequest request) throws Exception {
+ public void initBinder(WebDataBinder dataBinder, NativeWebRequest request) throws Exception {
for (InvocableHandlerMethod binderMethod : this.binderMethods) {
- if (isBinderMethodApplicable(binderMethod, binder)) {
- Object returnValue = binderMethod.invokeForRequest(request, null, binder);
+ if (isBinderMethodApplicable(binderMethod, dataBinder)) {
+ Object returnValue = binderMethod.invokeForRequest(request, null, dataBinder);
if (returnValue != null) {
throw new IllegalStateException(
"@InitBinder methods should return void: " + binderMethod);
@@ -79,11 +77,11 @@ public class InitBinderDataBinderFactory extends DefaultDataBinderFactory {
* the given WebDataBinder instance. By default we check the attributes
* names of the annotation, if present.
*/
- protected boolean isBinderMethodApplicable(HandlerMethod binderMethod, WebDataBinder binder) {
+ protected boolean isBinderMethodApplicable(HandlerMethod binderMethod, WebDataBinder dataBinder) {
InitBinder ann = binderMethod.getMethodAnnotation(InitBinder.class);
Assert.state(ann != null, "No InitBinder annotation");
String[] names = ann.value();
- return ObjectUtils.isEmpty(names) || Arrays.asList(names).contains(binder.getObjectName());
+ return (ObjectUtils.isEmpty(names) || ObjectUtils.containsElement(names, dataBinder.getObjectName()));
}
}
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/InitBinderBindingContext.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/InitBinderBindingContext.java
index f60e827e8ed..85e3f20ac87 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/InitBinderBindingContext.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/InitBinderBindingContext.java
@@ -16,8 +16,6 @@
package org.springframework.web.reactive.result.method.annotation;
-import java.util.Arrays;
-import java.util.Collection;
import java.util.List;
import org.springframework.lang.Nullable;
@@ -44,7 +42,6 @@ class InitBinderBindingContext extends BindingContext {
private final List binderMethods;
- /* Simple BindingContext to help with the invoking @InitBinder methods */
private final BindingContext binderMethodContext;
private final SessionStatus sessionStatus = new SimpleSessionStatus();
@@ -72,32 +69,28 @@ class InitBinderBindingContext extends BindingContext {
@Override
- protected WebExchangeDataBinder initDataBinder(WebExchangeDataBinder dataBinder,
- ServerWebExchange exchange) {
-
+ protected WebExchangeDataBinder initDataBinder(WebExchangeDataBinder dataBinder, ServerWebExchange exchange) {
this.binderMethods.stream()
.filter(binderMethod -> {
InitBinder ann = binderMethod.getMethodAnnotation(InitBinder.class);
Assert.state(ann != null, "No InitBinder annotation");
String[] names = ann.value();
- return ObjectUtils.isEmpty(names) || Arrays.asList(names).contains(dataBinder.getObjectName());
+ return (ObjectUtils.isEmpty(names) ||
+ ObjectUtils.containsElement(names, dataBinder.getObjectName()));
})
.forEach(method -> invokeBinderMethod(dataBinder, exchange, method));
return dataBinder;
}
- private void invokeBinderMethod(WebExchangeDataBinder dataBinder,
- ServerWebExchange exchange, SyncInvocableHandlerMethod binderMethod) {
-
- HandlerResult result = binderMethod.invokeForHandlerResult(
- exchange, this.binderMethodContext, dataBinder);
+ private void invokeBinderMethod(WebExchangeDataBinder dataBinder, ServerWebExchange exchange,
+ SyncInvocableHandlerMethod binderMethod) {
+ HandlerResult result = binderMethod.invokeForHandlerResult(exchange, this.binderMethodContext, dataBinder);
if (result != null && result.getReturnValue() != null) {
throw new IllegalStateException(
"@InitBinder methods should return void: " + binderMethod);
}
-
// Should not happen (no Model argument resolution) ...
if (!this.binderMethodContext.getModel().asMap().isEmpty()) {
throw new IllegalStateException(
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java
index 35698abb6ca..1980325b82f 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java
@@ -192,14 +192,14 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
@Override
@Nullable
- public BeanDefinition parse(Element element, ParserContext parserContext) {
- Object source = parserContext.extractSource(element);
- XmlReaderContext readerContext = parserContext.getReaderContext();
+ public BeanDefinition parse(Element element, ParserContext context) {
+ Object source = context.extractSource(element);
+ XmlReaderContext readerContext = context.getReaderContext();
CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);
- parserContext.pushContainingComponent(compDefinition);
+ context.pushContainingComponent(compDefinition);
- RuntimeBeanReference contentNegotiationManager = getContentNegotiationManager(element, source, parserContext);
+ RuntimeBeanReference contentNegotiationManager = getContentNegotiationManager(element, source, context);
RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
handlerMappingDef.setSource(source);
@@ -212,14 +212,14 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables);
}
- configurePathMatchingProperties(handlerMappingDef, element, parserContext);
+ configurePathMatchingProperties(handlerMappingDef, element, context);
readerContext.getRegistry().registerBeanDefinition(HANDLER_MAPPING_BEAN_NAME , handlerMappingDef);
- RuntimeBeanReference corsRef = MvcNamespaceUtils.registerCorsConfigurations(null, parserContext, source);
+ RuntimeBeanReference corsRef = MvcNamespaceUtils.registerCorsConfigurations(null, context, source);
handlerMappingDef.getPropertyValues().add("corsConfigurations", corsRef);
- RuntimeBeanReference conversionService = getConversionService(element, source, parserContext);
- RuntimeBeanReference validator = getValidator(element, source, parserContext);
+ RuntimeBeanReference conversionService = getConversionService(element, source, context);
+ RuntimeBeanReference validator = getValidator(element, source, context);
RuntimeBeanReference messageCodesResolver = getMessageCodesResolver(element);
RootBeanDefinition bindingDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class);
@@ -229,13 +229,13 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
bindingDef.getPropertyValues().add("validator", validator);
bindingDef.getPropertyValues().add("messageCodesResolver", messageCodesResolver);
- ManagedList> messageConverters = getMessageConverters(element, source, parserContext);
- ManagedList> argumentResolvers = getArgumentResolvers(element, parserContext);
- ManagedList> returnValueHandlers = getReturnValueHandlers(element, parserContext);
+ ManagedList> messageConverters = getMessageConverters(element, source, context);
+ ManagedList> argumentResolvers = getArgumentResolvers(element, context);
+ ManagedList> returnValueHandlers = getReturnValueHandlers(element, context);
String asyncTimeout = getAsyncTimeout(element);
RuntimeBeanReference asyncExecutor = getAsyncExecutor(element);
- ManagedList> callableInterceptors = getCallableInterceptors(element, source, parserContext);
- ManagedList> deferredResultInterceptors = getDeferredResultInterceptors(element, source, parserContext);
+ ManagedList> callableInterceptors = getCallableInterceptors(element, source, context);
+ ManagedList> deferredResultInterceptors = getDeferredResultInterceptors(element, source, context);
RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
handlerAdapterDef.setSource(source);
@@ -312,18 +312,18 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
defaultExceptionResolver.getPropertyValues().add("order", 2);
String defaultExResolverName = readerContext.registerWithGeneratedName(defaultExceptionResolver);
- parserContext.registerComponent(new BeanComponentDefinition(handlerMappingDef, HANDLER_MAPPING_BEAN_NAME));
- parserContext.registerComponent(new BeanComponentDefinition(handlerAdapterDef, HANDLER_ADAPTER_BEAN_NAME));
- parserContext.registerComponent(new BeanComponentDefinition(uriContributorDef, uriContributorName));
- parserContext.registerComponent(new BeanComponentDefinition(mappedInterceptorDef, mappedInterceptorName));
- parserContext.registerComponent(new BeanComponentDefinition(methodExceptionResolver, methodExResolverName));
- parserContext.registerComponent(new BeanComponentDefinition(statusExceptionResolver, statusExResolverName));
- parserContext.registerComponent(new BeanComponentDefinition(defaultExceptionResolver, defaultExResolverName));
+ context.registerComponent(new BeanComponentDefinition(handlerMappingDef, HANDLER_MAPPING_BEAN_NAME));
+ context.registerComponent(new BeanComponentDefinition(handlerAdapterDef, HANDLER_ADAPTER_BEAN_NAME));
+ context.registerComponent(new BeanComponentDefinition(uriContributorDef, uriContributorName));
+ context.registerComponent(new BeanComponentDefinition(mappedInterceptorDef, mappedInterceptorName));
+ context.registerComponent(new BeanComponentDefinition(methodExceptionResolver, methodExResolverName));
+ context.registerComponent(new BeanComponentDefinition(statusExceptionResolver, statusExResolverName));
+ context.registerComponent(new BeanComponentDefinition(defaultExceptionResolver, defaultExResolverName));
// Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not "turned off"
- MvcNamespaceUtils.registerDefaultComponents(parserContext, source);
+ MvcNamespaceUtils.registerDefaultComponents(context, source);
- parserContext.popAndRegisterContainingComponent();
+ context.popAndRegisterContainingComponent();
return null;
}
@@ -342,9 +342,7 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
}
}
- private RuntimeBeanReference getConversionService(
- Element element, @Nullable Object source, ParserContext parserContext) {
-
+ private RuntimeBeanReference getConversionService(Element element, @Nullable Object source, ParserContext context) {
RuntimeBeanReference conversionServiceRef;
if (element.hasAttribute("conversion-service")) {
conversionServiceRef = new RuntimeBeanReference(element.getAttribute("conversion-service"));
@@ -353,15 +351,15 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
RootBeanDefinition conversionDef = new RootBeanDefinition(FormattingConversionServiceFactoryBean.class);
conversionDef.setSource(source);
conversionDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
- String conversionName = parserContext.getReaderContext().registerWithGeneratedName(conversionDef);
- parserContext.registerComponent(new BeanComponentDefinition(conversionDef, conversionName));
+ String conversionName = context.getReaderContext().registerWithGeneratedName(conversionDef);
+ context.registerComponent(new BeanComponentDefinition(conversionDef, conversionName));
conversionServiceRef = new RuntimeBeanReference(conversionName);
}
return conversionServiceRef;
}
@Nullable
- private RuntimeBeanReference getValidator(Element element, @Nullable Object source, ParserContext parserContext) {
+ private RuntimeBeanReference getValidator(Element element, @Nullable Object source, ParserContext context) {
if (element.hasAttribute("validator")) {
return new RuntimeBeanReference(element.getAttribute("validator"));
}
@@ -370,8 +368,8 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
"org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean");
validatorDef.setSource(source);
validatorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
- String validatorName = parserContext.getReaderContext().registerWithGeneratedName(validatorDef);
- parserContext.registerComponent(new BeanComponentDefinition(validatorDef, validatorName));
+ String validatorName = context.getReaderContext().registerWithGeneratedName(validatorDef);
+ context.registerComponent(new BeanComponentDefinition(validatorDef, validatorName));
return new RuntimeBeanReference(validatorName);
}
else {
@@ -380,7 +378,7 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
}
private RuntimeBeanReference getContentNegotiationManager(
- Element element, @Nullable Object source, ParserContext parserContext) {
+ Element element, @Nullable Object source, ParserContext context) {
RuntimeBeanReference beanRef;
if (element.hasAttribute("content-negotiation-manager")) {
@@ -393,19 +391,19 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
factoryBeanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
factoryBeanDef.getPropertyValues().add("mediaTypes", getDefaultMediaTypes());
String name = CONTENT_NEGOTIATION_MANAGER_BEAN_NAME;
- parserContext.getReaderContext().getRegistry().registerBeanDefinition(name , factoryBeanDef);
- parserContext.registerComponent(new BeanComponentDefinition(factoryBeanDef, name));
+ context.getReaderContext().getRegistry().registerBeanDefinition(name , factoryBeanDef);
+ context.registerComponent(new BeanComponentDefinition(factoryBeanDef, name));
beanRef = new RuntimeBeanReference(name);
}
return beanRef;
}
private void configurePathMatchingProperties(
- RootBeanDefinition handlerMappingDef, Element element, ParserContext parserContext) {
+ RootBeanDefinition handlerMappingDef, Element element, ParserContext context) {
Element pathMatchingElement = DomUtils.getChildElementByTagName(element, "path-matching");
if (pathMatchingElement != null) {
- Object source = parserContext.extractSource(element);
+ Object source = context.extractSource(element);
if (pathMatchingElement.hasAttribute("suffix-pattern")) {
Boolean useSuffixPatternMatch = Boolean.valueOf(pathMatchingElement.getAttribute("suffix-pattern"));
@@ -424,14 +422,14 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
if (pathMatchingElement.hasAttribute("path-helper")) {
pathHelperRef = new RuntimeBeanReference(pathMatchingElement.getAttribute("path-helper"));
}
- pathHelperRef = MvcNamespaceUtils.registerUrlPathHelper(pathHelperRef, parserContext, source);
+ pathHelperRef = MvcNamespaceUtils.registerUrlPathHelper(pathHelperRef, context, source);
handlerMappingDef.getPropertyValues().add("urlPathHelper", pathHelperRef);
RuntimeBeanReference pathMatcherRef = null;
if (pathMatchingElement.hasAttribute("path-matcher")) {
pathMatcherRef = new RuntimeBeanReference(pathMatchingElement.getAttribute("path-matcher"));
}
- pathMatcherRef = MvcNamespaceUtils.registerPathMatcher(pathMatcherRef, parserContext, source);
+ pathMatcherRef = MvcNamespaceUtils.registerPathMatcher(pathMatcherRef, context, source);
handlerMappingDef.getPropertyValues().add("pathMatcher", pathMatcherRef);
}
}
@@ -483,18 +481,18 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
}
private ManagedList> getCallableInterceptors(
- Element element, @Nullable Object source, ParserContext parserContext) {
+ Element element, @Nullable Object source, ParserContext context) {
- ManagedList super Object> interceptors = new ManagedList<>();
+ ManagedList