@Test public void testEndpointMBeanExporterInParentChild() throws IntrospectionException, InstanceNotFoundException, MalformedObjectNameException, ReflectionException { this.context = new AnnotationConfigApplicationContext(); this.context.register( JmxAutoConfiguration.class, EndpointAutoConfiguration.class, EndpointMBeanExportAutoConfiguration.class); AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext(); parent.register( JmxAutoConfiguration.class, EndpointAutoConfiguration.class, EndpointMBeanExportAutoConfiguration.class); this.context.setParent(parent); parent.refresh(); this.context.refresh(); parent.close(); System.out.println("parent " + ObjectUtils.getIdentityHexString(parent)); System.out.println("child " + ObjectUtils.getIdentityHexString(this.context)); }
private void appendCache( Map<String, Object> output, Set<String> seen, Map<String, Object> input, String path) { synchronized (this.cache) { seen.add(ObjectUtils.getIdentityHexString(input)); for (Entry<String, Object> entry : input.entrySet()) { String key = entry.getKey(); if (StringUtils.hasText(path)) { if (key.startsWith("[")) { key = path + key; } else { key = path + "." + key; } } Object value = entry.getValue(); if (value instanceof String) { output.put(key, value); } else if (value instanceof Map) { // Need a compound key @SuppressWarnings("unchecked") Map<String, Object> map = (Map<String, Object>) value; output.put(key, map); if (!seen.contains(ObjectUtils.getIdentityHexString(map))) { appendCache(output, seen, map, key); } } else if (value instanceof Collection) { // Need a compound key @SuppressWarnings("unchecked") Collection<Object> collection = (Collection<Object>) value; output.put(key, collection); int count = 0; for (Object object : collection) { String index = "[" + (count++) + "]"; if (!seen.contains(ObjectUtils.getIdentityHexString(object))) { appendCache(output, seen, Collections.singletonMap(index, object), key); } else { output.put(key + index, object); } } } else { output.put(key, value); } } } }
/** Returns an instance of {@code ObjectName} based on the identity of the managed resource. */ public ObjectName getObjectName(Object managedBean, String beanKey) throws MalformedObjectNameException { String domain = ClassUtils.getPackageName(managedBean.getClass()); Hashtable keys = new Hashtable(); keys.put(TYPE_KEY, ClassUtils.getShortName(managedBean.getClass())); keys.put(HASH_CODE_KEY, ObjectUtils.getIdentityHexString(managedBean)); return ObjectNameManager.getInstance(domain, keys); }
/** * Returns a <code>StringBuffer</code> containing: * * <ol> * <li>the class name of the given object * <li>the character '@' * <li>the hex string for the object's identity hash code * </ol> * * <p>This method will return an empty <code>StringBuffer</code> if the given object is <code>null * </code>. * * @param obj the given object. * @return a <code>StringBuffer</code> containing identity information of the given object. */ public static StringBuffer identityToString(Object obj) { StringBuffer buffer = new StringBuffer(); if (obj != null) { buffer.append(obj.getClass().getName()); buffer.append("@"); buffer.append(ObjectUtils.getIdentityHexString(obj)); } return buffer; }
private ObjectName getObjectName( String domain, String beanKey, ApplicationContext applicationContext) throws MalformedObjectNameException { if (applicationContext.getParent() != null) { return ObjectNameManager.getInstance( String.format( "%s:type=Endpoint,name=%s,context=%s,identity=%s", domain, beanKey, ObjectUtils.getIdentityHexString(applicationContext), ObjectUtils.getIdentityHexString(applicationContext.getBean(beanKey)))); } else { return ObjectNameManager.getInstance( String.format( "%s:type=Endpoint,name=%s,identity=%s", domain, beanKey, ObjectUtils.getIdentityHexString(applicationContext.getBean(beanKey)))); } }
@Test public void testContainerBeanNameWhenNoGatewayBeanName() { JmsOutboundGateway gateway = new JmsOutboundGateway(); gateway.setConnectionFactory(mock(ConnectionFactory.class)); gateway.setRequestDestinationName("foo"); gateway.setUseReplyContainer(true); gateway.setReplyContainerProperties(new ReplyContainerProperties()); gateway.afterPropertiesSet(); assertEquals( "JMS_OutboundGateway@" + ObjectUtils.getIdentityHexString(gateway) + ".replyListener", TestUtils.getPropertyValue(gateway, "replyContainer.beanName")); }
private TaskExecutor createDefaultTaskExecutor() { // create thread-pool for starting contexts ThreadGroup threadGroup = new ThreadGroup( "eclipse-gemini-blueprint-extender[" + ObjectUtils.getIdentityHexString(this) + "]-threads"); threadGroup.setDaemon(false); SimpleAsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor(); taskExecutor.setThreadGroup(threadGroup); taskExecutor.setThreadNamePrefix("EclipseGeminiBlueprintExtenderThread-"); isTaskExecutorManagedInternally = true; return taskExecutor; }
/** * Generate a bean name for the given bean definition, unique within the given bean factory. * * @param beanDefinition the bean definition to generate a bean name for * @param beanFactory the bean factory that the definition is going to be registered with (to * check for existing bean names) * @param isInnerBean whether the given bean definition will be registered as inner bean or as * top-level bean (allowing for special name generation for inner beans vs. top-level beans) * @return the bean name to use * @throws BeanDefinitionStoreException if no unique name can be generated for the given bean * definition */ public static String generateBeanName( AbstractBeanDefinition beanDefinition, BeanDefinitionRegistry beanFactory, boolean isInnerBean) throws BeanDefinitionStoreException { String generatedId = beanDefinition.getBeanClassName(); if (generatedId == null) { if (beanDefinition instanceof ChildBeanDefinition) { generatedId = ((ChildBeanDefinition) beanDefinition).getParentName() + "$child"; } else if (beanDefinition.getFactoryBeanName() != null) { generatedId = beanDefinition.getFactoryBeanName() + "$created"; } } if (!StringUtils.hasText(generatedId)) { throw new BeanDefinitionStoreException( beanDefinition.getResourceDescription(), "", "Unnamed bean definition specifies neither 'class' nor 'parent' nor 'factory-bean'" + " - can't generate bean name"); } String id = generatedId; if (isInnerBean) { // Inner bean: generate identity hashcode suffix. id = generatedId + GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(beanDefinition); } else { // Top-level bean: use plain class name. If not already unique, // add counter - increasing the counter until the name is unique. int counter = 0; while (beanFactory.containsBeanDefinition(id)) { counter++; id = generatedId + GENERATED_BEAN_NAME_SEPARATOR + counter; } } return id; }
/** * Wrap the method invocation in a stateful retry with the policy and other helpers provided. If * there is a failure the exception will generally be re-thrown. The only time it is not re-thrown * is when retry is exhausted and the recovery path is taken (though the {@link * MethodInvocationRecoverer} provided if there is one). In that case the value returned from the * method invocation will be the value returned by the recoverer (so the return type for that * should be the same as the intercepted method). * * @see * org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation) * @see MethodInvocationRecoverer#recover(Object[], Throwable) */ @Override public Object invoke(final MethodInvocation invocation) throws Throwable { if (this.logger.isDebugEnabled()) { this.logger.debug( "Executing proxied method in stateful retry: " + invocation.getStaticPart() + "(" + ObjectUtils.getIdentityHexString(invocation) + ")"); } Object[] args = invocation.getArguments(); Object defaultKey = Arrays.asList(args); if (args.length == 1) { defaultKey = args[0]; } Object key = createKey(invocation, defaultKey); RetryState retryState = new DefaultRetryState( key, this.newMethodArgumentsIdentifier != null && this.newMethodArgumentsIdentifier.isNew(args), this.rollbackClassifier); Object result = this.retryOperations.execute( new MethodInvocationRetryCallback(invocation, label), this.recoverer != null ? new ItemRecovererCallback(args, this.recoverer) : null, retryState); if (this.logger.isDebugEnabled()) { this.logger.debug("Exiting proxied method in stateful retry with result: (" + result + ")"); } return result; }
@Override public void initializeNativeSession(Session session) { super.initializeNativeSession(session); this.id = ObjectUtils.getIdentityHexString(getNativeSession()); this.uri = session.getUpgradeRequest().getRequestURI(); this.headers = new HttpHeaders(); this.headers.putAll(getNativeSession().getUpgradeRequest().getHeaders()); this.headers = HttpHeaders.readOnlyHttpHeaders(headers); this.acceptedProtocol = session.getUpgradeResponse().getAcceptedSubProtocol(); List<ExtensionConfig> source = getNativeSession().getUpgradeResponse().getExtensions(); this.extensions = new ArrayList<WebSocketExtension>(source.size()); for (ExtensionConfig ec : source) { this.extensions.add(new WebSocketExtension(ec.getName(), ec.getParameters())); } if (this.user == null) { this.user = session.getUpgradeRequest().getUserPrincipal(); } }
/** * An abstract class for {@link SockJsService} implementations. Provides configuration support, * SockJS path resolution, and processing for static SockJS requests (e.g. "/info", "/iframe.html", * etc). Sub-classes are responsible for handling transport requests. * * <p>It is expected that this service is mapped correctly to one or more prefixes such as "/echo" * including all sub-URLs (e.g. "/echo/**"). A SockJS service itself is generally unaware of request * mapping details but nevertheless must be able to extract the SockJS path, which is the portion of * the request path following the prefix. In most cases, this class can auto-detect the SockJS path * but you can also explicitly configure the list of valid prefixes with {@link * #setValidSockJsPrefixes(String...)}. * * @author Rossen Stoyanchev * @since 4.0 */ public abstract class AbstractSockJsService implements SockJsService, SockJsConfiguration { protected final Log logger = LogFactory.getLog(getClass()); private static final int ONE_YEAR = 365 * 24 * 60 * 60; private String name = "SockJSService@" + ObjectUtils.getIdentityHexString(this); private String clientLibraryUrl = "https://d1fxtkz8shb9d2.cloudfront.net/sockjs-0.3.4.min.js"; private int streamBytesLimit = 128 * 1024; private boolean jsessionIdCookieRequired = true; private long heartbeatTime = 25 * 1000; private long disconnectDelay = 5 * 1000; private boolean webSocketsEnabled = true; private final TaskScheduler taskScheduler; private final List<String> validSockJsPrefixes = new ArrayList<String>(); private final Set<String> knownSockJsPrefixes = new CopyOnWriteArraySet<String>(); public AbstractSockJsService(TaskScheduler scheduler) { Assert.notNull(scheduler, "scheduler is required"); this.taskScheduler = scheduler; } /** A unique name for the service mainly for logging purposes. */ public void setName(String name) { this.name = name; } public String getName() { return this.name; } /** * Use this property to configure one or more prefixes that this SockJS service is allowed to * serve. The prefix (e.g. "/echo") is needed to extract the SockJS specific portion of the URL * (e.g. "${prefix}/info", "${prefix}/iframe.html", etc). * * <p>This property is not strictly required. In most cases, the SockJS path can be auto-detected * since the initial request from the SockJS client is of the form "{prefix}/info". Assuming the * SockJS service is mapped correctly (e.g. using Ant-style pattern "/echo/**") this should work * fine. This property can be used to configure explicitly the prefixes this service is allowed to * service. * * @param prefixes the prefixes to use; prefixes do not need to include the portions of the path * that represent Servlet container context or Servlet path. */ public void setValidSockJsPrefixes(String... prefixes) { this.validSockJsPrefixes.clear(); for (String prefix : prefixes) { if (prefix.endsWith("/") && (prefix.length() > 1)) { prefix = prefix.substring(0, prefix.length() - 1); } this.validSockJsPrefixes.add(prefix); } // sort with longest prefix at the top Collections.sort( this.validSockJsPrefixes, Collections.reverseOrder( new Comparator<String>() { @Override public int compare(String o1, String o2) { return new Integer(o1.length()).compareTo(new Integer(o2.length())); } })); } /** * Transports which don't support cross-domain communication natively (e.g. "eventsource", * "htmlfile") rely on serving a simple page (using the "foreign" domain) from an invisible * iframe. Code run from this iframe doesn't need to worry about cross-domain issues since it is * running from a domain local to the SockJS server. The iframe does need to load the SockJS * javascript client library and this option allows configuring its url. * * <p>By default this is set to point to * "https://d1fxtkz8shb9d2.cloudfront.net/sockjs-0.3.4.min.js". */ public AbstractSockJsService setSockJsClientLibraryUrl(String clientLibraryUrl) { this.clientLibraryUrl = clientLibraryUrl; return this; } /** * The URL to the SockJS JavaScript client library. * * @see #setSockJsClientLibraryUrl(String) */ public String getSockJsClientLibraryUrl() { return this.clientLibraryUrl; } public AbstractSockJsService setStreamBytesLimit(int streamBytesLimit) { this.streamBytesLimit = streamBytesLimit; return this; } @Override public int getStreamBytesLimit() { return streamBytesLimit; } /** * Some load balancers do sticky sessions, but only if there is a JSESSIONID cookie. Even if it is * set to a dummy value, it doesn't matter since session information is added by the load * balancer. * * <p>Set this option to indicate if a JSESSIONID cookie should be created. The default value is * "true". */ public AbstractSockJsService setJsessionIdCookieRequired(boolean jsessionIdCookieRequired) { this.jsessionIdCookieRequired = jsessionIdCookieRequired; return this; } /** * Whether setting JSESSIONID cookie is necessary. * * @see #setJsessionIdCookieRequired(boolean) */ public boolean isJsessionIdCookieRequired() { return this.jsessionIdCookieRequired; } public AbstractSockJsService setHeartbeatTime(long heartbeatTime) { this.heartbeatTime = heartbeatTime; return this; } @Override public long getHeartbeatTime() { return this.heartbeatTime; } @Override public TaskScheduler getTaskScheduler() { return this.taskScheduler; } /** * The amount of time in milliseconds before a client is considered disconnected after not having * a receiving connection, i.e. an active connection over which the server can send data to the * client. * * <p>The default value is 5000. */ public void setDisconnectDelay(long disconnectDelay) { this.disconnectDelay = disconnectDelay; } /** Return the amount of time in milliseconds before a client is considered disconnected. */ public long getDisconnectDelay() { return this.disconnectDelay; } /** * Some load balancers don't support websockets. This option can be used to disable the WebSocket * transport on the server side. * * <p>The default value is "true". */ public void setWebSocketsEnabled(boolean webSocketsEnabled) { this.webSocketsEnabled = webSocketsEnabled; } /** * Whether WebSocket transport is enabled. * * @see #setWebSocketsEnabled(boolean) */ public boolean isWebSocketEnabled() { return this.webSocketsEnabled; } /** * TODO * * @param request * @param response * @param sockJsPath * @throws Exception */ @Override public final void handleRequest( ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler handler) throws IOException, TransportErrorException { String sockJsPath = getSockJsPath(request); if (sockJsPath == null) { logger.warn( "Could not determine SockJS path for URL \"" + request.getURI().getPath() + ". Consider setting validSockJsPrefixes."); response.setStatusCode(HttpStatus.NOT_FOUND); return; } logger.debug(request.getMethod() + " with SockJS path [" + sockJsPath + "]"); try { request.getHeaders(); } catch (IllegalArgumentException ex) { // Ignore invalid Content-Type (TODO) } try { if (sockJsPath.equals("") || sockJsPath.equals("/")) { response .getHeaders() .setContentType(new MediaType("text", "plain", Charset.forName("UTF-8"))); response.getBody().write("Welcome to SockJS!\n".getBytes("UTF-8")); return; } else if (sockJsPath.equals("/info")) { this.infoHandler.handle(request, response); return; } else if (sockJsPath.matches("/iframe[0-9-.a-z_]*.html")) { this.iframeHandler.handle(request, response); return; } else if (sockJsPath.equals("/websocket")) { handleRawWebSocketRequest(request, response, handler); return; } String[] pathSegments = StringUtils.tokenizeToStringArray(sockJsPath.substring(1), "/"); if (pathSegments.length != 3) { logger.warn("Expected \"/{server}/{session}/{transport}\" but got \"" + sockJsPath + "\""); response.setStatusCode(HttpStatus.NOT_FOUND); return; } String serverId = pathSegments[0]; String sessionId = pathSegments[1]; String transport = pathSegments[2]; if (!validateRequest(serverId, sessionId, transport)) { response.setStatusCode(HttpStatus.NOT_FOUND); return; } handleTransportRequest( request, response, sessionId, TransportType.fromValue(transport), handler); } finally { response.flush(); } } /** Return the SockJS path or null if the path could not be determined. */ private String getSockJsPath(ServerHttpRequest request) { String path = request.getURI().getPath(); // SockJS prefix hints? if (!this.validSockJsPrefixes.isEmpty()) { for (String prefix : this.validSockJsPrefixes) { int index = path.indexOf(prefix); if (index != -1) { this.knownSockJsPrefixes.add(path.substring(0, index + prefix.length())); return path.substring(index + prefix.length()); } } return null; } // SockJS info request? if (path.endsWith("/info")) { this.knownSockJsPrefixes.add(path.substring(0, path.length() - "/info".length())); return "/info"; } // Have we seen this prefix before (following the initial /info request)? String match = null; for (String sockJsPath : this.knownSockJsPrefixes) { if (path.startsWith(sockJsPath)) { if ((match == null) || (match.length() < sockJsPath.length())) { match = sockJsPath; } } } if (match != null) { String result = path.substring(match.length()); Assert.isTrue( result.charAt(0) == '/', "Invalid SockJS path extracted from incoming path \"" + path + "\". The extracted SockJS path is \"" + result + "\". It was extracted from these known SockJS prefixes " + this.knownSockJsPrefixes + ". Consider setting 'validSockJsPrefixes' on DefaultSockJsService."); return result; } // SockJS greeting? String pathNoSlash = path.endsWith("/") ? path.substring(0, path.length() - 1) : path; String lastSegment = pathNoSlash.substring(pathNoSlash.lastIndexOf('/') + 1); if ((TransportType.fromValue(lastSegment) == null) && !lastSegment.startsWith("iframe")) { this.knownSockJsPrefixes.add(path); return ""; } return null; } protected abstract void handleRawWebSocketRequest( ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler webSocketHandler) throws IOException; protected abstract void handleTransportRequest( ServerHttpRequest request, ServerHttpResponse response, String sessionId, TransportType transportType, WebSocketHandler webSocketHandler) throws IOException, TransportErrorException; protected boolean validateRequest(String serverId, String sessionId, String transport) { if (!StringUtils.hasText(serverId) || !StringUtils.hasText(sessionId) || !StringUtils.hasText(transport)) { logger.warn("Empty server, session, or transport value"); return false; } // Server and session id's must not contain "." if (serverId.contains(".") || sessionId.contains(".")) { logger.warn("Server or session contain a \".\""); return false; } if (!isWebSocketEnabled() && transport.equals(TransportType.WEBSOCKET.value())) { logger.warn("Websocket transport is disabled"); return false; } return true; } protected void addCorsHeaders( ServerHttpRequest request, ServerHttpResponse response, HttpMethod... httpMethods) { String origin = request.getHeaders().getFirst("origin"); origin = ((origin == null) || origin.equals("null")) ? "*" : origin; response.getHeaders().add("Access-Control-Allow-Origin", origin); response.getHeaders().add("Access-Control-Allow-Credentials", "true"); List<String> accessControllerHeaders = request.getHeaders().get("Access-Control-Request-Headers"); if (accessControllerHeaders != null) { for (String header : accessControllerHeaders) { response.getHeaders().add("Access-Control-Allow-Headers", header); } } if (!ObjectUtils.isEmpty(httpMethods)) { response .getHeaders() .add( "Access-Control-Allow-Methods", StringUtils.arrayToDelimitedString(httpMethods, ", ")); response.getHeaders().add("Access-Control-Max-Age", String.valueOf(ONE_YEAR)); } } protected void addCacheHeaders(ServerHttpResponse response) { response.getHeaders().setCacheControl("public, max-age=" + ONE_YEAR); response.getHeaders().setExpires(new Date().getTime() + ONE_YEAR * 1000); } protected void addNoCacheHeaders(ServerHttpResponse response) { response.getHeaders().setCacheControl("no-store, no-cache, must-revalidate, max-age=0"); } protected void sendMethodNotAllowed(ServerHttpResponse response, List<HttpMethod> httpMethods) throws IOException { logger.debug("Sending Method Not Allowed (405)"); response.setStatusCode(HttpStatus.METHOD_NOT_ALLOWED); response.getHeaders().setAllow(new HashSet<HttpMethod>(httpMethods)); } private interface SockJsRequestHandler { void handle(ServerHttpRequest request, ServerHttpResponse response) throws IOException; } private static final Random random = new Random(); private final SockJsRequestHandler infoHandler = new SockJsRequestHandler() { private static final String INFO_CONTENT = "{\"entropy\":%s,\"origins\":[\"*:*\"],\"cookie_needed\":%s,\"websocket\":%s}"; @Override public void handle(ServerHttpRequest request, ServerHttpResponse response) throws IOException { if (HttpMethod.GET.equals(request.getMethod())) { response .getHeaders() .setContentType(new MediaType("application", "json", Charset.forName("UTF-8"))); addCorsHeaders(request, response); addNoCacheHeaders(response); String content = String.format( INFO_CONTENT, random.nextInt(), isJsessionIdCookieRequired(), isWebSocketEnabled()); response.getBody().write(content.getBytes()); } else if (HttpMethod.OPTIONS.equals(request.getMethod())) { response.setStatusCode(HttpStatus.NO_CONTENT); addCorsHeaders(request, response, HttpMethod.OPTIONS, HttpMethod.GET); addCacheHeaders(response); } else { sendMethodNotAllowed(response, Arrays.asList(HttpMethod.OPTIONS, HttpMethod.GET)); } } }; private final SockJsRequestHandler iframeHandler = new SockJsRequestHandler() { private static final String IFRAME_CONTENT = "<!DOCTYPE html>\n" + "<html>\n" + "<head>\n" + " <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n" + " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n" + " <script>\n" + " document.domain = document.domain;\n" + " _sockjs_onload = function(){SockJS.bootstrap_iframe();};\n" + " </script>\n" + " <script src=\"%s\"></script>\n" + "</head>\n" + "<body>\n" + " <h2>Don't panic!</h2>\n" + " <p>This is a SockJS hidden iframe. It's used for cross domain magic.</p>\n" + "</body>\n" + "</html>"; @Override public void handle(ServerHttpRequest request, ServerHttpResponse response) throws IOException { if (!HttpMethod.GET.equals(request.getMethod())) { sendMethodNotAllowed(response, Arrays.asList(HttpMethod.GET)); return; } String content = String.format(IFRAME_CONTENT, getSockJsClientLibraryUrl()); byte[] contentBytes = content.getBytes(Charset.forName("UTF-8")); StringBuilder builder = new StringBuilder("\"0"); DigestUtils.appendMd5DigestAsHex(contentBytes, builder); builder.append('"'); String etagValue = builder.toString(); List<String> ifNoneMatch = request.getHeaders().getIfNoneMatch(); if (!CollectionUtils.isEmpty(ifNoneMatch) && ifNoneMatch.get(0).equals(etagValue)) { response.setStatusCode(HttpStatus.NOT_MODIFIED); return; } response .getHeaders() .setContentType(new MediaType("text", "html", Charset.forName("UTF-8"))); response.getHeaders().setContentLength(contentBytes.length); addCacheHeaders(response); response.getHeaders().setETag(etagValue); response.getBody().write(contentBytes); } }; }
/** * Given a PropertyValue, return a value, resolving any references to other beans in the factory * if necessary. The value could be: * <li>A BeanDefinition, which leads to the creation of a corresponding new bean instance. * Singleton flags and names of such "inner beans" are always ignored: Inner beans are * anonymous prototypes. * <li>A RuntimeBeanReference, which must be resolved. * <li>A ManagedList. This is a special collection that may contain RuntimeBeanReferences or * Collections that will need to be resolved. * <li>A ManagedSet. May also contain RuntimeBeanReferences or Collections that will need to be * resolved. * <li>A ManagedMap. In this case the value may be a RuntimeBeanReference or Collection that will * need to be resolved. * <li>An ordinary object or {@code null}, in which case it's left alone. * * @param argName the name of the argument that the value is defined for * @param value the value object to resolve * @return the resolved object */ public Object resolveValueIfNecessary(Object argName, Object value) { // We must check each value to see whether it requires a runtime reference // to another bean to be resolved. if (value instanceof RuntimeBeanReference) { RuntimeBeanReference ref = (RuntimeBeanReference) value; return resolveReference(argName, ref); } else if (value instanceof RuntimeBeanNameReference) { String refName = ((RuntimeBeanNameReference) value).getBeanName(); refName = String.valueOf(doEvaluate(refName)); if (!this.beanFactory.containsBean(refName)) { throw new BeanDefinitionStoreException( "Invalid bean name '" + refName + "' in bean reference for " + argName); } return refName; } else if (value instanceof BeanDefinitionHolder) { // Resolve BeanDefinitionHolder: contains BeanDefinition with name and aliases. BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value; return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition()); } else if (value instanceof BeanDefinition) { // Resolve plain BeanDefinition, without contained name: use dummy name. BeanDefinition bd = (BeanDefinition) value; String innerBeanName = "(inner bean)" + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(bd); return resolveInnerBean(argName, innerBeanName, bd); } else if (value instanceof ManagedArray) { // May need to resolve contained runtime references. ManagedArray array = (ManagedArray) value; Class<?> elementType = array.resolvedElementType; if (elementType == null) { String elementTypeName = array.getElementTypeName(); if (StringUtils.hasText(elementTypeName)) { try { elementType = ClassUtils.forName(elementTypeName, this.beanFactory.getBeanClassLoader()); array.resolvedElementType = elementType; } catch (Throwable ex) { // Improve the message by showing the context. throw new BeanCreationException( this.beanDefinition.getResourceDescription(), this.beanName, "Error resolving array type for " + argName, ex); } } else { elementType = Object.class; } } return resolveManagedArray(argName, (List<?>) value, elementType); } else if (value instanceof ManagedList) { // May need to resolve contained runtime references. return resolveManagedList(argName, (List<?>) value); } else if (value instanceof ManagedSet) { // May need to resolve contained runtime references. return resolveManagedSet(argName, (Set<?>) value); } else if (value instanceof ManagedMap) { // May need to resolve contained runtime references. return resolveManagedMap(argName, (Map<?, ?>) value); } else if (value instanceof ManagedProperties) { Properties original = (Properties) value; Properties copy = new Properties(); for (Map.Entry<Object, Object> propEntry : original.entrySet()) { Object propKey = propEntry.getKey(); Object propValue = propEntry.getValue(); if (propKey instanceof TypedStringValue) { propKey = evaluate((TypedStringValue) propKey); } if (propValue instanceof TypedStringValue) { propValue = evaluate((TypedStringValue) propValue); } copy.put(propKey, propValue); } return copy; } else if (value instanceof TypedStringValue) { // Convert value to target type here. TypedStringValue typedStringValue = (TypedStringValue) value; Object valueObject = evaluate(typedStringValue); try { Class<?> resolvedTargetType = resolveTargetType(typedStringValue); if (resolvedTargetType != null) { return this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType); } else { return valueObject; } } catch (Throwable ex) { // Improve the message by showing the context. throw new BeanCreationException( this.beanDefinition.getResourceDescription(), this.beanName, "Error converting typed String value for " + argName, ex); } } else { return evaluate(value); } }