I am trying to configure spring global method security with AspectJ advice mode so I can use #PreAuthorize annotations in all #Configurable annotated classes. This my java configs:
#Configuration
#EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true, mode = AdviceMode.ASPECTJ)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration
and:
#EnableCaching
#SpringBootApplication
#EnableSpringConfigured
#EnableTransactionManagement(mode = AdviceMode.ASPECTJ)
#EnableLoadTimeWeaving(aspectjWeaving = EnableLoadTimeWeaving.AspectJWeaving.ENABLED)
public class WebApplication extends WebMvcConfigurerAdapter
This is my #Configurable class:
#Configurable
public class Entity {
#PreAuthorize("hasPermission(this, 'publish')")
public void method() { }
}
I also added spring-security-aspects as dependency. From AspectJ logs I can clearly see that Spring security related aspects are applied on my #Configurable classes however as soon as I create instance of these classes I get this exception:
Post-processor tried to replace bean instance of type [com.example.Entity] with (proxy) object of type [com.sun.proxy.$Proxy130] - not supported for aspect-configured classes!
I am using spring boot version 1.2.1 therefore spring security version is 3.2.5 . This seems to be bug that was discussed here : Spring Security AspectJMode with #EnableGlobalMethodSecurity not working
However this bug should not affect my version of spring security... Is there any workaround for this issue?
Ok I have solved this. It was problem with spring boot's SecurityAutoConfiguration class. I had to exclude it from auto configuration and configre spring security manually - not very big deal, but anyway...
Related
I am creating my own spring boot starter to centralise some common configurations in my projects. I would like to let on of my #Configuration classes be only matched, if my spring boot app is annotated in a certain way like so:
#SpringBootApplication
#EnableResourceServer
public class MyApplication {
...
When i use #ConditionalOnClass:
#Configuration
#ConditionalOnClass({EnableResourceServer.class})
class ResourceServerAutoConfiguration
the auto configuration matched when the dependency is used even when the app is not a resource server (annotation is not present).
Is there a condition that only matches when the spring boot app has a certain annotation present?
I believe the simplest way would be to
Add the #Import annotation to your #EnableResourceServer annotation class and pass in your configuration class
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Import(ResourceServerAutoConfiguration.class)
public #interface EnableResourceServer {
}
Remove ResourceServerAutoConfiguration from the auto configuration block of the spring.factories file so it is no longer autoconfigured.
This should result in the config only being loaded when the annotation is present ie.
#SpringBootApplication
#EnableResourceServer
public class NotificationAdapterApplication {
}
I'm new to Spring and testing a Spring Data project with Postgresql/JPA and MongoDB components. My Test class has the following annotations:
#SpringBootApplication
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {SpringMongoConfig.class, PgRepository.class, MongodbRepository.class})
public class PerfTest {
#Autowired
private PgRepository pgRepo;
#Autowired
private MongodbRepository mongoRep;
For some reason the spring-context module is trying to load WebMvcConfigurer while resolving bean classes, giving me a NoClassDefFoundError.
Is the Spring Boot Autoconfigure trying to initiate a full web controller suite? If so, why? I'm really just interested in Spring Data. Should I avoid Spring Boot entirely?
You shouldn't annotate a test class as a #SpringBootApplication. This annotation is used to define a class in your main code base which contains a main() method to spin up your Spring boot container with auto-configuration.
If it's Spring data you are interested in testing then your tests will need to point to a #Configuration class which is annotated with #EnableJpaRepositories this will allow your repository interfaces to be autowired.
I don't know what is in your SpringMongoConfig class but if this contains that annotation then all you need to do is:
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = {SpringMongoConfig.class})
public class PerfTest {
If not then you need to set up this configuration and include it in the #ContextConfiguration of the test.
Another option which is a bit more heavyweight but will guarantee everything is available for your test (provided your Spring boot application is set up correctly) is to mark your test with #SpringBootTest this will automatically load the whole Spring boot context for the application. If it has trouble finding your main class you can point it in the right direction by providing the class in the annotation:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = MyMainClass.class)
public class PerfTest {
You need to add #Component to your repository interface. Spring loads the component class first and then #AutoWiring & Initialization of variables will happen.
In a Spring Boot project that is not using JPA/Hibernate (but which cannot help but have these libraries on the classpath; long story, but completely unchangeable in this context), I need to stop whatever autoconfiguration is causing the error:
java.lang.IllegalArgumentException: At least one JPA metamodel must be present!
I am aware that I have to explicitly exclude JPA/Hibernate autoconfiguration. I do so in both the #SpringBootApplication-annotated Java class and also in the application.properties file.
#SpringBootApplication
#EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class })
#ComponentScan(basePackages = { "com" })
#EnableAsync
public class Application extends SpringBootServletInitializer {
...
}
and
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
Additionally, I've verified that these autoconfigurations are being excluded, by looking in the --debug output:
Exclusions:
-----------
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
Still, it fails when I don't have a JPA #Entity defined.
Why would this be?
I have a pretty simple Spring Boot project that was just upgraded from Spring Boot 1.2.5.RELEASE to Spring Boot 1.3.0.M5 (which then relies on Spring 4.2.0.RELEASE), and now my project won't compile.
Project:
#Configuration
#ComponentScan
#EnableAutoConfiguration
#EnableEncryptableProperties
public class MyApp extends WebMvcConfigurerAdapter {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}
Test that fails compilation (my only test ATM):
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = {MyApp.class})
#DirtiesContext
public class MyDAO_DataTest {
#Autowired
MyDAO dao;
#Test
public void whenDoingAtest() throws Exception {
//...
}
}
When I try to compile, it fails on my test file, saying:
org.springframework.core.annotation.AnnotationConfigurationException: In AnnotationAttributes for annotation [org.springframework.test.context.ContextConfiguration] declared on [class com.example.MyDAO_DataTest], attribute [locations] and its alias [value] are declared with values of [{}] and [{class com.example.MyApp}], but only one declaration is permitted.
I found the feature that's the origin of the exception, but I don't really understand what I can do about it.
Update I "fixed" the issue by changing this line:
#SpringApplicationConfiguration(classes = {MyApp.class})
... to this:
#ContextConfiguration(classes = {MyApp.class},
loader = SpringApplicationContextLoader.class)
effectively working around the issue and allowing myself to work, but I don't understand why I had to. #SpringApplicationConfiguration is described as Similar to the standard ContextConfiguration but uses Spring Boot's SpringApplicationContextLoader, so what's the deal?
Spring Boot 1.3.0.M5 (which then relies on Spring 4.2.0.RELEASE)
That is unfortunately incorrect: Spring Boot 1.3.0.M5 depends explicitly on Spring Framework 4.2.1, not 4.2.0.
The exception you are seeing was addressed in Spring Framework 4.2.1, specifically in the following issues.
https://jira.spring.io/browse/SPR-13325
https://jira.spring.io/browse/SPR-13345
And changes made to #SpringApplicationConfiguration in Spring Boot 1.3.0 M5 require Spring Framework 4.2.1. See the following issue for details.
https://github.com/spring-projects/spring-boot/issues/3635
Thus, ensuring that you are running against Spring Framework 4.2.1 should resolve your problem.
Regards,
Sam
I spent some time resolving problem with missing org.joda.time.DateTime->java.util.Date converter in Spring Data (which should be enabled by default when Joda-Time is on a classpath). I have found a reason, but it generated a question about #Configuration annotation in Spring.
Standard application config using AbstractMongoConfiguration from spring-data-mongodb:
#Configuration
#ComponentScan
#EnableMongoRepositories
public class AppConfig extends AbstractMongoConfiguration { ... }
A test which explicit uses AppConfig class (with Spock, but internally mechanisms provided by spring-test are used):
#ContextConfiguration(classes = AppConfig)
class JodaDocRepositorySpec extends Specification {
#Autowired
private JodaDocRepository jodaDocRepository
def "save document with DateTime"() {
given:
def jodaDoc = new JodaDoc(DateTime.now())
when:
def savedJodaDoc = jodaDocRepository.save(jodaDoc)
then:
savedJodaDoc.id
}
}
It works fine. But when #Configuration annotation in AppConfig is removed/commented:
//#Configuration
#ComponentScan
#EnableMongoRepositories
public class AppConfig extends AbstractMongoConfiguration { ... }
the test fails with:
org.springframework.core.convert.ConverterNotFoundException:
No converter found capable of converting from type org.joda.time.DateTime to type java.util.Date
AFAIK it is not needed to use #Configuration for the configuration class when it is explicit registered in the context (by classes in #ContextConfiguration or a register() method in AnnotationConfigWebApplicationContext). The classes are processed anyway and all declared beans are found. It is sometimes useful to not use #Configuration to prevent detecting by a component scan when there are 2 similar configuration classes in the same packages in a test context used by different tests.
Therefor I think it could a bug in Spring which causes to different internal beans processing in the context depending on an usage or not a #Configuration annotation. I compared Spring logs from these two cases and there are some differences, but I'm not able to determine what are they caused by in the Spring internal classes. Before a bug submission I would like to ask:
My question. Is there an explicable reason why Spring for the same configuration class (pointed explicit in #ContextConfiguration) uses (or not) converters for Joda-Time depending on an existence of a #Configuration annotation?
I created also a quickstart project reproducing the issue. spring-data-mongodb 1.3.3, spring 4.0.0, joda-time 2.3.
It's everything OK in this behaviour. AbstractMongoConfiguration is annotated by #Configuration, but in fact this annotation is not #Inherited, so you have to explicitly annotate your class.
When you remove #Configuration annotation then your AppConfig class is not a full configuration. It's processes as a lite configuration just because it contains methods annotated by #Bean - please refer to methods in org.springframework.context.annotation.ConfigurationClassUtils
isFullConfigurationCandidate()
isLiteConfigurationCandidate()
isFullConfigurationClass()
Finally only full (annotated by #Configuration) configuration classes are processes and enhanced by configuration post processors - look at ConfigurationClassPostProcessor.enhanceConfigurationClasses()