<dependencies>
- <!-- Spring -->
+ <!-- Spring-Boot-Autoconfiguration -->
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-autoconfigure</artifactId>
+ <optional>true</optional>
+ </dependency>
<dependency>
<groupId>org.springframework.social</groupId>
<artifactId>spring-social-facebook</artifactId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-configuration-processor</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>javax.servlet-api</artifactId>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
--- /dev/null
+package de.juplo.facebook.errors;
+
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration;
+import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.oauth2.client.OAuth2RestTemplate;
+import org.springframework.security.oauth2.client.http.OAuth2ErrorHandler;
+
+
+/**
+ * Automatic configuration for Srping-Security-OAuth2
+ *
+ * @author Kai Moritz
+ */
+@Configuration
+@ConditionalOnClass(value = OAuth2RestTemplate.class)
+@AutoConfigureAfter({
+ WebMvcAutoConfiguration.class,
+ OAuth2AutoConfiguration.class
+ })
+public class FacebookErrorsOAuth2AutoConfiguration
+{
+ private static final Logger LOG =
+ LoggerFactory.getLogger(FacebookErrorsOAuth2AutoConfiguration.class);
+
+ @Bean
+ static public BeanPostProcessor errorHandlerInjectorOAuth2()
+ {
+ LOG.info("Configuring OAuth2GraphApiErrorHandler for handling error-messages");
+
+ return new BeanPostProcessor()
+ {
+ @Override
+ public Object postProcessBeforeInitialization(
+ Object bean,
+ String beanName
+ )
+ throws
+ BeansException
+ {
+ if (bean instanceof OAuth2RestTemplate)
+ {
+ LOG.debug("Injecting OAuth2GraphApiErrorHandler in {}", bean);
+ OAuth2RestTemplate template = (OAuth2RestTemplate) bean;
+ template.setErrorHandler(
+ new OAuth2GraphApiErrorHandler(
+ (OAuth2ErrorHandler)template.getErrorHandler()
+ )
+ );
+ }
+
+ return bean;
+ }
+
+ @Override
+ public Object postProcessAfterInitialization(
+ Object bean,
+ String beanName
+ )
+ throws
+ BeansException
+ {
+ return bean;
+ }
+ };
+ }
+}
--- /dev/null
+package de.juplo.facebook.errors;
+
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanCreationException;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.social.FacebookAutoConfiguration;
+import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.social.facebook.api.Facebook;
+import org.springframework.social.facebook.api.impl.FacebookTemplate;
+import org.springframework.web.client.ResponseErrorHandler;
+import org.springframework.web.client.RestTemplate;
+
+
+
+/**
+ * Automatic configuration for Srping-Social-Facebook
+ *
+ * @author Kai Moritz
+ */
+@Configuration
+@ConditionalOnClass(value = FacebookTemplate.class)
+@AutoConfigureAfter({
+ WebMvcAutoConfiguration.class,
+ FacebookAutoConfiguration.class
+ })
+public class FacebookErrorsSpringSocialAutoConfiguration
+{
+ private static final Logger LOG =
+ LoggerFactory.getLogger(FacebookErrorsSpringSocialAutoConfiguration.class);
+
+
+ @Bean
+ static public BeanPostProcessor errorHandlerInjectorSpringSocial()
+ {
+ LOG.info("Configuring GraphApiErrorHandler for handling error-messages");
+ return new BeanPostProcessor()
+ {
+ @Override
+ public Object postProcessBeforeInitialization(
+ Object bean,
+ String beanName
+ )
+ throws
+ BeansException
+ {
+ return bean;
+ }
+
+ @Override
+ public Object postProcessAfterInitialization(
+ Object bean,
+ String beanName
+ )
+ throws
+ BeansException
+ {
+ if (bean instanceof Facebook)
+ {
+ try
+ {
+ Facebook facebook = (Facebook) bean;
+ RestTemplate template = (RestTemplate) facebook.restOperations();
+ ResponseErrorHandler handler = template.getErrorHandler();
+ template.setErrorHandler(new GraphApiErrorHandler(handler));
+ // Be sure, that the potential exception is triggered before!
+ LOG.debug("Injecting GraphApiErrorHandler in {}", facebook);
+ }
+ catch (BeanCreationException e)
+ {
+ /**
+ * This exception is called, if the BeanPostProcessor is called
+ * with a scoped bean, while the according scope is not
+ * accessible.
+ * This happens during initialization and can safely be ignored,
+ * because we only have to inject the handler for beans, that are
+ * actually usable.
+ */
+ }
+ }
+
+ return bean;
+ }
+ };
+ }
+}
\ No newline at end of file
--- /dev/null
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+de.juplo.facebook.errors.SpringSocialAutoConfiguration,\
+de.juplo.facebook.errors.OAuth2AutoConfiguration
--- /dev/null
+package de.juplo.facebook.errors;
+
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import org.junit.After;
+import org.junit.Test;
+import org.springframework.context.annotation.Configuration;
+import static org.junit.Assert.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer;
+import org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.mock.env.MockEnvironment;
+import org.springframework.security.oauth2.client.OAuth2RestTemplate;
+import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
+
+
+
+public class FacebookErrorsOAuth2AutoConfigurationTest
+{
+ private final Logger LOG =
+ LoggerFactory.getLogger(FacebookErrorsOAuth2AutoConfigurationTest.class);
+
+
+ private ConfigurableApplicationContext context;
+
+
+ @After
+ public void tearDown()
+ {
+ if (this.context != null)
+ this.context.close();
+ }
+
+
+ @Test
+ public void defaultNonWebConfiguration()
+ {
+ LOG.info("<-- Start Of New Test-Case!");
+ Map<String, String> properties = new HashMap<>();
+ properties.put("security.oauth2.client.client-id", "CLIENT_ID");
+ context = loadNonWebApplicationContext(EmptyConfiguration.class, properties);
+ OAuth2RestTemplate template = context.getBean(OAuth2RestTemplate.class);
+ assertEquals(OAuth2GraphApiErrorHandler.class, template.getErrorHandler().getClass());
+ }
+
+ @Test
+ public void defaultWebConfiguration()
+ {
+ LOG.info("<-- Start Of New Test-Case!");
+ Map<String, String> properties = new HashMap<>();
+ properties.put("security.oauth2.client.client-id", "CLIENT_ID");
+ context = loadWebApplicationContext(EmptyConfiguration.class, properties);
+ OAuth2RestTemplate template = context.getBean(OAuth2RestTemplate.class);
+ assertEquals(OAuth2GraphApiErrorHandler.class, template.getErrorHandler().getClass());
+ }
+
+
+ @Configuration
+ static class EmptyConfiguration
+ {
+ }
+
+
+ private ConfigurableApplicationContext loadNonWebApplicationContext(
+ Class<?> config,
+ Map<String, String> properties
+ )
+ {
+ AnnotationConfigApplicationContext ctx =
+ new AnnotationConfigApplicationContext();
+ if (properties != null)
+ {
+ MockEnvironment env = new MockEnvironment();
+ for (Entry<String, String> entry : properties.entrySet())
+ env.withProperty(entry.getKey(), entry.getValue());
+ ctx.setEnvironment(env);
+ }
+ ctx.register(FacebookErrorsOAuth2AutoConfiguration.class);
+ ctx.register(OAuth2AutoConfiguration.class);
+ ctx.register(config);
+ AutoConfigurationReportLoggingInitializer report =
+ new AutoConfigurationReportLoggingInitializer();
+ report.initialize(ctx);
+ ctx.refresh();
+ return ctx;
+ }
+
+ private ConfigurableApplicationContext loadWebApplicationContext(
+ Class<?> config,
+ Map<String, String> properties
+ )
+ {
+ AnnotationConfigWebApplicationContext ctx =
+ new AnnotationConfigWebApplicationContext();
+ if (properties != null)
+ {
+ MockEnvironment env = new MockEnvironment();
+ for (Entry<String, String> entry : properties.entrySet())
+ env.withProperty(entry.getKey(), entry.getValue());
+ ctx.setEnvironment(env);
+ }
+ ctx.register(FacebookErrorsOAuth2AutoConfiguration.class);
+ ctx.register(OAuth2AutoConfiguration.class);
+ ctx.register(config);
+ AutoConfigurationReportLoggingInitializer report =
+ new AutoConfigurationReportLoggingInitializer();
+ report.initialize(ctx);
+ ctx.refresh();
+ return ctx;
+ }
+}
--- /dev/null
+package de.juplo.facebook.errors;
+
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import org.junit.After;
+import org.junit.Test;
+import org.springframework.context.annotation.Configuration;
+import static org.junit.Assert.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer;
+import org.springframework.boot.autoconfigure.social.FacebookAutoConfiguration;
+import org.springframework.boot.autoconfigure.social.SocialWebAutoConfiguration;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Scope;
+import org.springframework.context.annotation.ScopedProxyMode;
+import org.springframework.mock.env.MockEnvironment;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.social.connect.ConnectionRepository;
+import org.springframework.social.facebook.api.Facebook;
+import org.springframework.social.facebook.api.impl.FacebookTemplate;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
+
+
+
+public class FacebookErrorsSpringSocialAutoConfigurationTest
+{
+ private final Logger LOG =
+ LoggerFactory.getLogger(FacebookErrorsSpringSocialAutoConfigurationTest.class);
+
+
+ private ConfigurableApplicationContext context;
+
+
+ @After
+ public void tearDown()
+ {
+ if (this.context != null)
+ this.context.close();
+ }
+
+
+ @Test
+ public void defaultConfiguration()
+ {
+ LOG.info("<-- Start Of New Test-Case!");
+ Map<String, String> properties = new HashMap<>();
+ properties.put("spring.social.facebook.app-id", "APP_ID");
+ properties.put("spring.social.facebook.app-secret", "APP_SECRET");
+ context = loadWebApplicationContext(EmptyConfiguration.class, properties);
+ Facebook facebook = context.getBean("facebook", Facebook.class);
+ RestTemplate template = (RestTemplate) facebook.restOperations();
+ assertEquals(GraphApiErrorHandler.class, template.getErrorHandler().getClass());
+ }
+
+
+ @Configuration
+ static class EmptyConfiguration
+ {
+ /**
+ * We have to provide this scoped bean for all our tests.
+ * Otherwise, the tests will fail, if we do not set up a complete
+ * environment with a connection-repository and a properly mocked request,
+ * that holds appropriate information to fetch a connection from that
+ * repository.
+ * @param repository
+ * @return
+ */
+ @Bean
+ @Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES)
+ public Facebook facebook(ConnectionRepository repository)
+ {
+ return new FacebookTemplate("ACCESS_TOKEN");
+ }
+ }
+
+
+ private ConfigurableApplicationContext loadWebApplicationContext(
+ Class<?> config,
+ Map<String, String> properties
+ )
+ {
+ AnnotationConfigWebApplicationContext ctx =
+ new AnnotationConfigWebApplicationContext();
+ if (properties != null)
+ {
+ MockEnvironment env = new MockEnvironment();
+ for (Entry<String, String> entry : properties.entrySet())
+ env.withProperty(entry.getKey(), entry.getValue());
+ ctx.setEnvironment(env);
+ }
+ ctx.register(FacebookErrorsSpringSocialAutoConfiguration.class);
+ ctx.register(FacebookAutoConfiguration.class);
+ ctx.register(SocialWebAutoConfiguration.class);
+ ctx.register(config);
+ AutoConfigurationReportLoggingInitializer report =
+ new AutoConfigurationReportLoggingInitializer();
+ report.initialize(ctx);
+ MockHttpServletRequest request = new MockHttpServletRequest();
+ ServletRequestAttributes attributes = new ServletRequestAttributes(request);
+ RequestContextHolder.setRequestAttributes(attributes);
+ ctx.refresh();
+ return ctx;
+ }
+}
<level value="trace"/>
</logger>
+ <logger name="org.springframework.boot.autoconfigure.logging">
+ <level value="debug"/>
+ </logger>
+
<root>
<level value="info"/>
<appender-ref ref="CONSOLE"/>