Custom `RelyingPartyRegistrationRepository` implementation - java

It looks like Spring always uses InMemoryRelyingPartyRegistrationRepository to return a RelyingPartyRegistrationRepository typed bean, refer to https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyRegistrationConfiguration.java.
Question: how can I inject (autowire) my own implementation of RelyingPartyRegistrationRepository? Say I would like to allow the auto wired relying party repository auto reload from database once I have SAML configuration for a certain customer updated. Is this doable?

You can provide your own bean and spring boot auto configuration will back off.
#Configuration
#EnableConfigurationProperties(Saml2RelyingPartyProperties.class)
public class SamlConfig{
#Bean
RelyingPartyRegistrationRepository relyingPartyRegistrationRepository(Saml2RelyingPartyProperties properties) {
-- Provide custom repository implementation
}
}
You may need other changes after you create your own bean based on what you need.

Related

is it possible to have Spring configuration relying only on annotations apart from being spring boot application?

I'm new in Spring applications, and see the big difference between configurations in springBoot and spring. So my questin is: apart from spring-boot, is there a way to setup a proper spring application(with web mvc, security, aop, ...), without any xml config file (ie : config relying only on annotations).
Yes, there is a way to do this in Spring. Spring Boot is after all an enhanced, autoconfigured Spring (with other cool features). That means that everything there is in Spring Boot should be achievable in Spring as well, but you would have do a bit/a lot of Your own extra work.
Moving straight to the point, in order to achieve what you want, you would need to undertake the following steps:
Create a class, which will store all the configuration (basically the properties you would store in the xml file) - let's call it AppConfig.class
Annotate the AppConfig.class with #Configuration - this will inform Spring that this class is the source of configuration;
Annotate the AppConfig.class with #ComponentScan("com.app") - here, You need to provide a package, from which Spring has to start component scanning in order to find Beans to be registered in Spring Container. Important note is, that it will scan the package and it's subpackages, so you would mostly want to provide here the top level package;
If you need some data to be injected into your beans, you would want to use the #PropertySource("classpath:application.properties") - I have provided here the default value, which Spring Boot uses internally in case you want to inject some data into your beans at runtime. For this to work, you need to inject into AppConfig.class an Environment.class
To show it on the example:
#Configuration
#ComponentScan("com.app")
#PropertySource("classpath:application.properties")
public class AppConfig {
// it will help to pull the properties incorporated in the file you have provided in the #PropertySource annotation
private Environment environment;
//inject it
public AppConfig(Environment environment) {
this.environment = environment;
}
// build your beans - the getProperty method accepts the key from application.properties
// file and return a value as a String. You can provide additional arguments to convert
//the value and a default value if the property is not found
#Bean
public Product product() {
return new Product(
environment.getProperty("product.name", "XXX"),
environment.getProperty("product.price", BigDecimal.class, BigDecimal.ZERO),
environment.getProperty("product.quantity", Integer.class, 10)
);
}
}
I hope that it helps

Spring Boot Autoconfigured ObjectMapper plus additional ObjectMapper

We are currently trying to implement a JSON Logging library making use of spring auto configuration or create its Jackson ObjectMapper. Our aim is to not override the spring auto configuration in class JacksonAutoConfiguration so that every customization by clients of the logging library won't be disabled.
The actual spring behavior is bean based and our main problem is that the JacksonProperties are not customizable and reusable for us. If we actually add a second bean of JacksonProperties the application start up would fail because JacksonAutoConfiguration.Jackson2ObjectMapperBuilderCustomizerConfiguration.class won't be able to handle a second bean. (The Spring Boot internal one is not annotated as #Primary.)
So what we did was start reimplementing every bean like the builder, customizer and so on. But this is not very maintainable as it duplicates framework code.
Our question now is if there would be any way to adapt the way of creating data sources for jackson object mapper beans. An example of creating data sources would be a following one.
#Bean(name = "testDataSource")
#ConfigurationProperties(prefix = "test.datasource")
public HikariDataSource naeDataSource(DataSourceProperties testDataSourceProperties) {
return testDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
}
We know the problem would still be that overriding the object mapper would deactivate it but if you pay attention to the application context it would be much easier to offer multiple object mapper instances.
Or is there any easier or other way we did not find so far?
Versions used:
Spring-Boot 2.0.5.RELEASE
UPDATE
I forked the spring boot project, made some changes to Spring Boot Autoconfiguration module and also set up a small demo project. I do not think it is the perfect way but with this changes it would be possible to initialize own object mapper easily from configuration properties. For example you can now easily create five object mapper for five different rest templates and clients called via REST-API.
#ConfigurationProperties(prefix = "logging.jackson")
#Bean("loggingJacksonProperties")
public JacksonProperties loggingJacksonProperties() {
return new JacksonProperties();
}
#Bean
public ObjectMapper secondObjectMapper(#Qualifier("loggingJacksonProperties") JacksonProperties loggingJacksonProperties) {
return loggingJacksonProperties.initializeJackson2ObjectMapperBuilder().build();
}
Comparing-Fork: https://github.com/spring-projects/spring-boot/compare/2.1.x...mixaaaa:feature/jackson_properties_initializer
Demo-Project: https://github.com/mixaaaa/jackson-demo

Spring default bean candidate

I'm writing a library that uses spring, for others to use. In my library, I have class A that has an interface B as a field (with #Autowired).
I have a default implementation of that field, but the user can implement a custom implementation by himself. What I want to happen is the following:
If the user implemented B, I want that bean to be injected to A, otherwise I want my default implementation to be injected.
Something like the opposite of #Primary
I know that the user can add the #Primary annotation in order for that to happen, but I don't want him to add any other annotation besides #Component (because it is not clear for the user why he must add the #Primary annotation)
Is there a way to achieve this behavior? I've also tried #Order and #Priority, but no luck - the user must add another annotation.
Thanks!
You should create your own auto configuration. Auto configuration classes are always processed last so user's own configuration is processed first and when using #Conditional... annotations user's beans will take precedence.
Your auto configuration class should look like this:
#Configuration
public class MyAutoConfiguration {
#ConditionalOnMissingBean(B.class)
#Bean
public B defaultImplementation() { return A(); }
#Bean
public UsesB classThatUsesB(B b) { return UsesB(b); }
}
In this case if the user of your library defines a bean of type B it will always be used first and if they don't the bean created by the defaultImplementation method will be used.
I don't believe so. Spring's #Autowired is rather specific. Making it perform differently without any configuration changes (either to XML or the Spring configuration class) is pretty much impossible.

How does Java Spring #Autowired work with interface inheriting from several interfaces?

I have a Java Spring Framework project. After a bit of googling I found a way to include custom JPA methods into a JpaRepository. The injection of my repository into my service class using #Autowired works, but I can't understand how Spring handles the injection in this case. Could someone explain how Spring does the injection of CalendarEventRepository into CalendarEventService when the method implementations are in separate classes. It finds the JpaRepository implementation somewhere and my own custom implementation class with my custom method. Howcome their methods are accessible through the same reference variable calendarEventRepository? Bonus question: how does Spring find and instantiate the implementation for JpaRepository?
public interface CalendarEventRepository extends JpaRepository<CalendarEvent, Long>, CalendarEventRepositoryCustom { }
public interface CalendarEventRepositoryCustom {
public List<CalendarEvent> findCalendarEventsBySearchCriteria(CalendarEventSearchCriteria searchCriteria);
}
public class CalendarEventRepositoryImpl implements
CalendarEventRepositoryCustom {
public List<CalendarEvent> findCalendarEventsBySearchCriteria(CalendarEventSearchCriteria searchCriteria) {
}
}
public class CalendarEventService {
#Autowired
CalendarEventRepository calendarEventRepository;
...
calendarEventRepository.delete(calendarEvent);
...
return calendarEventRepository.findCalendarEventsBySearchCriteria(searchCriteria);
...
}
Thanks in advance!
When you are using Spring JPA repository interface (extend JpaRepository class), the important thing is that the implementation of the interface is generated at runtime. Method names are used by Spring to determine what the method should (since you have written the name findCalendarEventsBySearchCriteria correctly, it means that you already know that). In your particular case, CalendarEventRepository extends CalendarEventRepositoryCustom and therefore has a method findCalendarEventsBySearchCriteria(...), and also extends JpaRepository<CalendarEvent, Long>, which means that it should be treated as JPA repository, and the corresponding implementation should be generated.
To enable the generation of the repository implementation, you need to either include <jpa:repositories base-package="..." /> to your XML configuration file, or #Configuration #EnableJpaRepositories(basePackage = "...") When you have these, that's all the information Spring needs to generate (instantiate) repository and add it to application contexts, and the inject it into other beans. In your case, #Autowired CalendarEventRepository calendarEventRepository; specifies where it should be injected. I guess it more answers bonus question than the main one, but seems better to start with it.
I haven't yet touched CalendarEventRepositoryImpl. You should use such class if you want to drop the mentioned generation of repository implementation for particular methods. Spring looks for a class which name equals to repository interface's name + "Impl". If such class exists, Spring merges its methods with generated ones. So, see for yourself whether auto-generated findCalendarEventsBySearchCriteria method fits your needs or you want to implement it yourself. If the generated one fits, you should consider removing CalendarEventRepositoryImpl at all.
Could someone explain how Spring does the injection of
CalendarEventRepository into CalendarEventService when the method
implementations are in separate classes.
Answer: First, and most important - all Spring beans are managed - they "live" inside a container, called "application context".
Regardless of which type of configuration you are usin (Java or xml based) you enable "Component Scanning" this helps Spring determine which resource to inject.
How spring determines which bean to inject:
Matches the names.
Matches the type.
You even use Qualifiers to narrow down the search for spring.
It finds the JpaRepository implementation somewhere and my own
custom implementation class with my custom method. Howcome their
methods are accessible through the same reference variable
calendarEventRepository?
This is more of a java core question of inheritance. Since JpaRepository, CalendarEventRepositoryCustom and CalendarEventRepository are the base classes (implementations) of your CalendarEventRepositoryImpl so any method/field that is public or protected is available to CalendarEventRepositoryImpl class.
Here you are using "Program though interface" your reference variable here is calendarEventRepository which is an interface (parent) and that is why you are able to access the fields/methods.
Bonus question: how does Spring find and instantiate the
implementation for JpaRepository?
In spring configuration (java based) you tell spring to search for JPARepositories as below:
#EnableJpaRepositories(
basePackages = {
"com.package"}
, entityManagerFactoryRef = "EntityManagerFactory", transactionManagerRef = "jpaTransactionManager"
)
This is how spring gets to know which beans to create.
I recommend reading out Spring in Action (2nd to 4th Edition) by Craig Walls.
You can as well go through the https://spring.io/docs
Annotations (Autowired, Inject, your custom) works because of AOP. Read a bit about AOP and you will know how that works.

I need to invoke a Spring Service from a java class, how to set the active profile for spring application from java class

*I need to invoke a spring service from my java class, how would i set the active profile dynamically for spring service.
here's the code
java code
public void abc() {
AccountDetailService service = new AccountDetailService();
service.getAccountDetails();
}
AccountDetailService
#Profile
#Log
#Component
private void getAccountDetails() {
String filename=environment.getProperty("fileName");
accountDaoImpl.getDetails(filename);
}
i have various profiles like dev,qa and prod
how would i pass active profiles from my java class when invoking spring service.*
You don't need to pass any profiles to your service. Simply, create configurations for different profiles. These configurations will provide the correct service instance for given profile. Here you have an example of such configuration class:
#Configuration
#Profile(value = "test")
public class ServiceTestConfig
{
#Bean
public Service service()
{
return new TestService();
}
}
Create another configuration with other #Profile annotation and Spring will automatically create proper instances. You can set active profile in many ways, the simplest is to change the spring.profiles.active property in your application.properties. Refer to Spring documentation to learn more about profiles:
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html
Update
If you really need to pass your active profile to your service in runtime, you can inject Environment instance and call getActiveProfiles(). See the javadoc: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/env/Environment.html. Just keep in mind it's not the way profiles should be used in Spring. The example I provided before is considered the best practice.

Categories

Resources