@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
/ *
* Copyright 2013 - 2015 the original author or authors .
* Copyright 2012 - 2015 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,33 +16,21 @@
@@ -16,33 +16,21 @@
package org.springframework.boot.actuate.endpoint ;
import java.io.IOException ;
import java.io.InputStream ;
import java.util.ArrayList ;
import java.util.Collection ;
import java.util.Collections ;
import java.util.HashMap ;
import java.util.HashSet ;
import java.util.List ;
import java.util.Map ;
import java.util.Set ;
import org.apache.commons.logging.Log ;
import org.apache.commons.logging.LogFactory ;
import org.springframework.beans.BeanWrapperImpl ;
import org.springframework.beans.BeansException ;
import org.springframework.boot.context.properties.ConfigurationBeanFactoryMetaData ;
import org.springframework.boot.context.properties.ConfigurationProperties ;
import org.springframework.context.ApplicationContext ;
import org.springframework.context.ApplicationContextAware ;
import org.springframework.core.io.Resource ;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver ;
import org.springframework.util.ClassUtils ;
import org.springframework.util.StringUtils ;
import com.fasterxml.jackson.core.JsonParseException ;
import com.fasterxml.jackson.databind.BeanDescription ;
import com.fasterxml.jackson.databind.JsonMappingException ;
import com.fasterxml.jackson.databind.ObjectMapper ;
import com.fasterxml.jackson.databind.SerializationConfig ;
import com.fasterxml.jackson.databind.SerializationFeature ;
@ -76,17 +64,10 @@ public class ConfigurationPropertiesReportEndpoint extends
@@ -76,17 +64,10 @@ public class ConfigurationPropertiesReportEndpoint extends
private static final String CGLIB_FILTER_ID = "cglibFilter" ;
private static final Log logger = LogFactory
. getLog ( ConfigurationPropertiesReportEndpoint . class ) ;
private final Sanitizer sanitizer = new Sanitizer ( ) ;
private ApplicationContext context ;
private ConfigurationPropertiesMetaData metadata ;
private String metadataLocations = "classpath:*/META-INF/*spring-configuration-metadata.json" ;
public ConfigurationPropertiesReportEndpoint ( ) {
super ( "configprops" ) ;
}
@ -100,14 +81,6 @@ public class ConfigurationPropertiesReportEndpoint extends
@@ -100,14 +81,6 @@ public class ConfigurationPropertiesReportEndpoint extends
this . sanitizer . setKeysToSanitize ( keysToSanitize ) ;
}
/ * *
* Location path for JSON metadata about config properties .
* @param metadataLocations the metadataLocations to set
* /
public void setMetadataLocations ( String metadataLocations ) {
this . metadataLocations = metadataLocations ;
}
@Override
public Map < String , Object > invoke ( ) {
return extract ( this . context ) ;
@ -174,13 +147,10 @@ public class ConfigurationPropertiesReportEndpoint extends
@@ -174,13 +147,10 @@ public class ConfigurationPropertiesReportEndpoint extends
* /
private Map < String , Object > safeSerialize ( ObjectMapper mapper , Object bean ,
String prefix ) {
if ( this . metadata = = null ) {
this . metadata = new ConfigurationPropertiesMetaData ( this . metadataLocations ) ;
}
try {
@SuppressWarnings ( "unchecked" )
Map < String , Object > result = new HashMap < String , Object > ( mapper . convertValue (
this . metadata . extractMap ( bean , prefix ) , Map . class ) ) ;
bean , Map . class ) ) ;
return result ;
}
catch ( Exception ex ) {
@ -349,152 +319,4 @@ public class ConfigurationPropertiesReportEndpoint extends
@@ -349,152 +319,4 @@ public class ConfigurationPropertiesReportEndpoint extends
}
}
/ * *
* Convenience class for grabbing and caching valid property names from
* / META - INF / spring - configuration - metadata . json so that metadata that is known to be
* valid can be used to pull the correct nested properties out of beans that might
* otherwise be tricky ( contain cycles or other unserializable properties ) .
* /
protected static class ConfigurationPropertiesMetaData {
private final String metadataLocations ;
private final Map < String , Set < String > > matched = new HashMap < String , Set < String > > ( ) ;
private Set < String > keys = null ;
public ConfigurationPropertiesMetaData ( String metadataLocations ) {
this . metadataLocations = metadataLocations ;
}
public boolean matches ( String prefix ) {
if ( this . matched . containsKey ( prefix ) ) {
return matchesInternal ( prefix ) ;
}
synchronized ( this . matched ) {
if ( this . matched . containsKey ( prefix ) ) {
return matchesInternal ( prefix ) ;
}
this . matched . put ( prefix , findKeys ( prefix ) ) ;
}
return matchesInternal ( prefix ) ;
}
private boolean matchesInternal ( String prefix ) {
return this . matched . get ( prefix ) ! = null ;
}
private Set < String > findKeys ( String prefix ) {
HashSet < String > keys = new HashSet < String > ( ) ;
for ( String key : getKeys ( ) ) {
if ( key . length ( ) > prefix . length ( )
& & key . startsWith ( prefix )
& & "." . equals ( key . substring ( prefix . length ( ) , prefix . length ( ) + 1 ) ) ) {
keys . add ( key . substring ( prefix . length ( ) + 1 ) ) ;
}
}
return ( keys . isEmpty ( ) ? null : keys ) ;
}
private Set < String > getKeys ( ) {
if ( this . keys ! = null ) {
return this . keys ;
}
this . keys = new HashSet < String > ( ) ;
try {
ObjectMapper mapper = new ObjectMapper ( ) ;
Resource [ ] resources = new PathMatchingResourcePatternResolver ( )
. getResources ( this . metadataLocations ) ;
for ( Resource resource : resources ) {
addKeys ( mapper , resource ) ;
}
}
catch ( IOException ex ) {
logger . warn ( "Could not deserialize config properties metadata" , ex ) ;
}
return this . keys ;
}
@SuppressWarnings ( "unchecked" )
private void addKeys ( ObjectMapper mapper , Resource resource ) throws IOException ,
JsonParseException , JsonMappingException {
InputStream inputStream = resource . getInputStream ( ) ;
Map < String , Object > map = mapper . readValue ( inputStream , Map . class ) ;
Collection < Map < String , Object > > metadata = ( Collection < Map < String , Object > > ) map
. get ( "properties" ) ;
for ( Map < String , Object > value : metadata ) {
try {
if ( value . containsKey ( "type" ) ) {
this . keys . add ( ( String ) value . get ( "name" ) ) ;
}
}
catch ( Exception ex ) {
logger . warn ( "Could not parse config properties metadata" , ex ) ;
}
}
}
public Object extractMap ( Object bean , String prefix ) {
if ( ! matches ( prefix ) ) {
return bean ;
}
Map < String , Object > map = new HashMap < String , Object > ( ) ;
for ( String key : this . matched . get ( prefix ) ) {
addProperty ( bean , key , map ) ;
}
return map ;
}
@SuppressWarnings ( "unchecked" )
private void addProperty ( Object bean , String key , Map < String , Object > map ) {
String prefix = ( key . contains ( "." ) ? StringUtils . split ( key , "." ) [ 0 ] : key ) ;
String suffix = ( key . length ( ) > prefix . length ( ) ? key . substring ( prefix
. length ( ) + 1 ) : null ) ;
String property = prefix ;
if ( bean instanceof Map ) {
Map < String , Object > value = ( Map < String , Object > ) bean ;
bean = new MapHolder ( value ) ;
property = "map[" + property + "]" ;
}
BeanWrapperImpl wrapper = new BeanWrapperImpl ( bean ) ;
try {
Object value = wrapper . getPropertyValue ( property ) ;
if ( value instanceof Map ) {
Map < String , Object > nested = new HashMap < String , Object > ( ) ;
map . put ( prefix , nested ) ;
if ( suffix ! = null ) {
addProperty ( value , suffix , nested ) ;
}
}
else {
map . put ( prefix , value ) ;
}
}
catch ( Exception ex ) {
// Probably just lives on a different bean (it happens)
logger . debug ( "Could not parse config properties metadata '" + key + "': "
+ ex . getMessage ( ) ) ;
}
}
protected static class MapHolder {
Map < String , Object > map = new HashMap < String , Object > ( ) ;
public MapHolder ( Map < String , Object > bean ) {
this . map . putAll ( bean ) ;
}
public Map < String , Object > getMap ( ) {
return this . map ;
}
public void setMap ( Map < String , Object > map ) {
this . map = map ;
}
}
}
}