Skip to content

Commit 46c46db

Browse files
author
Phillip Webb
committed
Refine Spring Social auto-configuration
Refine auto-configuration for Spring Social to: - Only auto-configure FB/Twitter/LinkedIn if the `app-id` property is set. - Only configure ConnectController and ProviderSignInController if there is a ConnectionFactoryLocator. - Auto-configure Spring Social's SpringSocialDialect for Thymeleaf if Thymeleaf is present. - Added several tests around Spring Social auto-configuration. Fixes gh-1118
1 parent 179e155 commit 46c46db

File tree

10 files changed

+270
-72
lines changed

10 files changed

+270
-72
lines changed

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/social/FacebookAutoConfiguration.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.springframework.boot.autoconfigure.social;
1818

1919
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
20+
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
2021
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
2122
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2223
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -29,6 +30,7 @@
2930
import org.springframework.context.annotation.Scope;
3031
import org.springframework.context.annotation.ScopedProxyMode;
3132
import org.springframework.social.config.annotation.EnableSocial;
33+
import org.springframework.social.config.annotation.SocialConfigurerAdapter;
3234
import org.springframework.social.connect.Connection;
3335
import org.springframework.social.connect.ConnectionFactory;
3436
import org.springframework.social.connect.ConnectionRepository;
@@ -46,7 +48,9 @@
4648
* @since 1.1.0
4749
*/
4850
@Configuration
49-
@ConditionalOnClass({ FacebookConnectionFactory.class })
51+
@ConditionalOnClass({ SocialConfigurerAdapter.class, FacebookConnectionFactory.class })
52+
@ConditionalOnProperty(prefix = "spring.social.facebook.", value = "app-id")
53+
@AutoConfigureBefore(SocialWebAutoConfiguration.class)
5054
@AutoConfigureAfter(WebMvcAutoConfiguration.class)
5155
public class FacebookAutoConfiguration {
5256

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/social/LinkedInAutoConfiguration.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.springframework.boot.autoconfigure.social;
1818

1919
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
20+
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
2021
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
2122
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2223
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -29,6 +30,7 @@
2930
import org.springframework.context.annotation.Scope;
3031
import org.springframework.context.annotation.ScopedProxyMode;
3132
import org.springframework.social.config.annotation.EnableSocial;
33+
import org.springframework.social.config.annotation.SocialConfigurerAdapter;
3234
import org.springframework.social.connect.Connection;
3335
import org.springframework.social.connect.ConnectionFactory;
3436
import org.springframework.social.connect.ConnectionRepository;
@@ -45,7 +47,9 @@
4547
* @since 1.1.0
4648
*/
4749
@Configuration
48-
@ConditionalOnClass({ LinkedInConnectionFactory.class })
50+
@ConditionalOnClass({ SocialConfigurerAdapter.class, LinkedInConnectionFactory.class })
51+
@ConditionalOnProperty(prefix = "spring.social.linkedin.", value = "app-id")
52+
@AutoConfigureBefore(SocialWebAutoConfiguration.class)
4953
@AutoConfigureAfter(WebMvcAutoConfiguration.class)
5054
public class LinkedInAutoConfiguration {
5155

@@ -69,7 +73,7 @@ protected ConnectionFactory<?> createConnectionFactory(
6973
}
7074

7175
@Bean
72-
@ConditionalOnMissingBean(LinkedInConnectionFactory.class)
76+
@ConditionalOnMissingBean(LinkedIn.class)
7377
@Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES)
7478
public LinkedIn linkedin(ConnectionRepository repository) {
7579
Connection<LinkedIn> connection = repository

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/social/SocialAutoConfigurerAdapter.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package org.springframework.boot.autoconfigure.social;
1818

19-
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2019
import org.springframework.boot.bind.RelaxedPropertyResolver;
2120
import org.springframework.context.EnvironmentAware;
2221
import org.springframework.core.env.Environment;
@@ -31,7 +30,6 @@
3130
* @author Phillip Webb
3231
* @since 1.1.0
3332
*/
34-
@ConditionalOnClass(SocialConfigurerAdapter.class)
3533
abstract class SocialAutoConfigurerAdapter extends SocialConfigurerAdapter implements
3634
EnvironmentAware {
3735

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/social/SocialWebAutoConfiguration.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@
2020

2121
import org.springframework.beans.factory.annotation.Autowired;
2222
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
23+
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
2324
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
2425
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
2526
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2627
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
2728
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
2829
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
2930
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
31+
import org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration;
3032
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
3133
import org.springframework.context.annotation.Bean;
3234
import org.springframework.context.annotation.Configuration;
@@ -45,10 +47,12 @@
4547
import org.springframework.social.connect.web.ProviderSignInController;
4648
import org.springframework.social.connect.web.ProviderSignInInterceptor;
4749
import org.springframework.social.connect.web.SignInAdapter;
50+
import org.springframework.social.connect.web.thymeleaf.SpringSocialDialect;
4851
import org.springframework.util.Assert;
4952
import org.springframework.util.CollectionUtils;
5053
import org.springframework.web.servlet.ViewResolver;
5154
import org.springframework.web.servlet.view.BeanNameViewResolver;
55+
import org.thymeleaf.spring4.SpringTemplateEngine;
5256

5357
/**
5458
* {@link EnableAutoConfiguration Auto-configuration} for Spring Social's web connection
@@ -59,6 +63,8 @@
5963
*/
6064
@Configuration
6165
@ConditionalOnClass({ ConnectController.class, SocialConfigurerAdapter.class })
66+
@ConditionalOnBean({ ConnectionFactoryLocator.class, UsersConnectionRepository.class })
67+
@AutoConfigureBefore(ThymeleafAutoConfiguration.class)
6268
@AutoConfigureAfter(WebMvcAutoConfiguration.class)
6369
public class SocialWebAutoConfiguration {
6470

@@ -119,7 +125,7 @@ public ProviderSignInController signInController(
119125
@Configuration
120126
@EnableSocial
121127
@ConditionalOnWebApplication
122-
@ConditionalOnMissingClass(name="org.springframework.security.core.context.SecurityContextHolder")
128+
@ConditionalOnMissingClass(name = "org.springframework.security.core.context.SecurityContextHolder")
123129
protected static class AnonymousUserIdSourceConfig extends SocialConfigurerAdapter {
124130

125131
@Override
@@ -131,7 +137,6 @@ public String getUserId() {
131137
}
132138
};
133139
}
134-
135140
}
136141

137142
@Configuration
@@ -148,6 +153,18 @@ public UserIdSource getUserIdSource() {
148153

149154
}
150155

156+
@Configuration
157+
@ConditionalOnClass(SpringTemplateEngine.class)
158+
protected static class SpringSocialThymeleafConfig {
159+
160+
@Bean
161+
@ConditionalOnMissingBean
162+
public SpringSocialDialect springSocialDialect() {
163+
return new SpringSocialDialect();
164+
}
165+
166+
}
167+
151168
private static class SecurityContextUserIdSource implements UserIdSource {
152169

153170
@Override

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/social/TwitterAutoConfiguration.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.springframework.boot.autoconfigure.social;
1818

1919
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
20+
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
2021
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
2122
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2223
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -29,6 +30,7 @@
2930
import org.springframework.context.annotation.Scope;
3031
import org.springframework.context.annotation.ScopedProxyMode;
3132
import org.springframework.social.config.annotation.EnableSocial;
33+
import org.springframework.social.config.annotation.SocialConfigurerAdapter;
3234
import org.springframework.social.connect.Connection;
3335
import org.springframework.social.connect.ConnectionFactory;
3436
import org.springframework.social.connect.ConnectionRepository;
@@ -46,7 +48,9 @@
4648
* @since 1.1.0
4749
*/
4850
@Configuration
49-
@ConditionalOnClass({ TwitterConnectionFactory.class })
51+
@ConditionalOnClass({ SocialConfigurerAdapter.class, TwitterConnectionFactory.class })
52+
@ConditionalOnProperty(prefix = "spring.social.twitter.", value = "app-id")
53+
@AutoConfigureBefore(SocialWebAutoConfiguration.class)
5054
@AutoConfigureAfter(WebMvcAutoConfiguration.class)
5155
public class TwitterAutoConfiguration {
5256

@@ -69,7 +73,7 @@ protected ConnectionFactory<?> createConnectionFactory(
6973
}
7074

7175
@Bean
72-
@ConditionalOnMissingBean(TwitterConnectionFactory.class)
76+
@ConditionalOnMissingBean
7377
@Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES)
7478
public Twitter twitter(ConnectionRepository repository) {
7579
Connection<Twitter> connection = repository
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright 2012-2014 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.social;
18+
19+
import org.junit.After;
20+
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
21+
import org.springframework.social.UserIdSource;
22+
import org.springframework.social.connect.ConnectionFactoryLocator;
23+
import org.springframework.social.connect.ConnectionRepository;
24+
import org.springframework.social.connect.UsersConnectionRepository;
25+
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
26+
27+
import static org.junit.Assert.assertNotNull;
28+
import static org.junit.Assert.fail;
29+
30+
/**
31+
* Abstract base class for testing Spring Social auto-configuration.
32+
*
33+
* @author Craig Walls
34+
*/
35+
public class AbstractSocialAutoConfigurationTests {
36+
37+
protected AnnotationConfigWebApplicationContext context;
38+
39+
@After
40+
public void close() {
41+
if (this.context != null) {
42+
this.context.close();
43+
}
44+
}
45+
46+
public AbstractSocialAutoConfigurationTests() {
47+
super();
48+
}
49+
50+
protected void assertConnectionFrameworkBeans() {
51+
assertNotNull(this.context.getBean(UsersConnectionRepository.class));
52+
assertNotNull(this.context.getBean(ConnectionRepository.class));
53+
assertNotNull(this.context.getBean(ConnectionFactoryLocator.class));
54+
assertNotNull(this.context.getBean(UserIdSource.class));
55+
}
56+
57+
protected void assertNoConnectionFrameworkBeans() {
58+
assertMissingBean(UsersConnectionRepository.class);
59+
assertMissingBean(ConnectionRepository.class);
60+
assertMissingBean(ConnectionFactoryLocator.class);
61+
assertMissingBean(UserIdSource.class);
62+
}
63+
64+
protected void assertMissingBean(Class<?> beanClass) {
65+
try {
66+
assertNotNull(this.context.getBean(beanClass));
67+
fail("Unexpected bean in context of type " + beanClass.getName());
68+
}
69+
catch (NoSuchBeanDefinitionException ex) {
70+
}
71+
}
72+
73+
}

spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/social/FacebookAutoConfigurationTests.java

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,33 +16,19 @@
1616

1717
package org.springframework.boot.autoconfigure.social;
1818

19-
import org.junit.After;
2019
import org.junit.Test;
2120
import org.springframework.boot.test.EnvironmentTestUtils;
22-
import org.springframework.social.UserIdSource;
23-
import org.springframework.social.connect.ConnectionFactoryLocator;
24-
import org.springframework.social.connect.ConnectionRepository;
25-
import org.springframework.social.connect.UsersConnectionRepository;
2621
import org.springframework.social.facebook.api.Facebook;
2722
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
2823

2924
import static org.junit.Assert.assertNotNull;
3025

3126
/**
3227
* Tests for {@link FacebookAutoConfiguration}.
33-
*
28+
*
3429
* @author Craig Walls
3530
*/
36-
public class FacebookAutoConfigurationTests {
37-
38-
private AnnotationConfigWebApplicationContext context;
39-
40-
@After
41-
public void close() {
42-
if (this.context != null) {
43-
this.context.close();
44-
}
45-
}
31+
public class FacebookAutoConfigurationTests extends AbstractSocialAutoConfigurationTests {
4632

4733
@Test
4834
public void expectedSocialBeansCreated() throws Exception {
@@ -51,14 +37,20 @@ public void expectedSocialBeansCreated() throws Exception {
5137
"spring.social.facebook.appId:12345");
5238
EnvironmentTestUtils.addEnvironment(this.context,
5339
"spring.social.facebook.appSecret:secret");
54-
this.context.register(SocialWebAutoConfiguration.class);
5540
this.context.register(FacebookAutoConfiguration.class);
41+
this.context.register(SocialWebAutoConfiguration.class);
5642
this.context.refresh();
57-
assertNotNull(this.context.getBean(UsersConnectionRepository.class));
58-
assertNotNull(this.context.getBean(ConnectionRepository.class));
59-
assertNotNull(this.context.getBean(ConnectionFactoryLocator.class));
60-
assertNotNull(this.context.getBean(UserIdSource.class));
43+
assertConnectionFrameworkBeans();
6144
assertNotNull(this.context.getBean(Facebook.class));
6245
}
6346

47+
@Test
48+
public void noFacebookBeanCreatedWhenPropertiesArentSet() throws Exception {
49+
this.context = new AnnotationConfigWebApplicationContext();
50+
this.context.register(FacebookAutoConfiguration.class);
51+
this.context.register(SocialWebAutoConfiguration.class);
52+
this.context.refresh();
53+
assertNoConnectionFrameworkBeans();
54+
assertMissingBean(Facebook.class);
55+
}
6456
}

spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/social/LinkedInAutoConfigurationTests.java

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,33 +16,19 @@
1616

1717
package org.springframework.boot.autoconfigure.social;
1818

19-
import org.junit.After;
2019
import org.junit.Test;
2120
import org.springframework.boot.test.EnvironmentTestUtils;
22-
import org.springframework.social.UserIdSource;
23-
import org.springframework.social.connect.ConnectionFactoryLocator;
24-
import org.springframework.social.connect.ConnectionRepository;
25-
import org.springframework.social.connect.UsersConnectionRepository;
2621
import org.springframework.social.linkedin.api.LinkedIn;
2722
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
2823

2924
import static org.junit.Assert.assertNotNull;
3025

3126
/**
3227
* Tests for {@link LinkedInAutoConfiguration}.
33-
*
28+
*
3429
* @author Craig Walls
3530
*/
36-
public class LinkedInAutoConfigurationTests {
37-
38-
private AnnotationConfigWebApplicationContext context;
39-
40-
@After
41-
public void close() {
42-
if (this.context != null) {
43-
this.context.close();
44-
}
45-
}
31+
public class LinkedInAutoConfigurationTests extends AbstractSocialAutoConfigurationTests {
4632

4733
@Test
4834
public void expectedSocialBeansCreated() throws Exception {
@@ -51,14 +37,21 @@ public void expectedSocialBeansCreated() throws Exception {
5137
"spring.social.linkedin.appId:12345");
5238
EnvironmentTestUtils.addEnvironment(this.context,
5339
"spring.social.linkedin.appSecret:secret");
54-
this.context.register(SocialWebAutoConfiguration.class);
5540
this.context.register(LinkedInAutoConfiguration.class);
41+
this.context.register(SocialWebAutoConfiguration.class);
5642
this.context.refresh();
57-
assertNotNull(this.context.getBean(UsersConnectionRepository.class));
58-
assertNotNull(this.context.getBean(ConnectionRepository.class));
59-
assertNotNull(this.context.getBean(ConnectionFactoryLocator.class));
60-
assertNotNull(this.context.getBean(UserIdSource.class));
43+
assertConnectionFrameworkBeans();
6144
assertNotNull(this.context.getBean(LinkedIn.class));
6245
}
6346

47+
@Test
48+
public void noLinkedInBeanCreatedIfPropertiesArentSet() throws Exception {
49+
this.context = new AnnotationConfigWebApplicationContext();
50+
this.context.register(LinkedInAutoConfiguration.class);
51+
this.context.register(SocialWebAutoConfiguration.class);
52+
this.context.refresh();
53+
assertNoConnectionFrameworkBeans();
54+
assertMissingBean(LinkedIn.class);
55+
}
56+
6457
}

0 commit comments

Comments
 (0)