Spring Profiles not recognized in a Web Application - spring

I'm trying to implement Spring Profiles to load a specific class implementation based on the profile specified. The profile to use is specified as a property (spring.profiles.active) within a properties file included in the classpath.
Source here: https://github.com/overattribution/spring-profile-test
public interface MyService {
public void doSomething();
}
#Service
#Profile("preprod")
public class MyServicePreProdImpl implements MyService {
private final Logger LOG = LoggerFactory.getLogger(MyServicePreProdImpl.class);
#Override
public void doSomething() {
LOG.debug("Doing something in " + MyServicePreProdImpl.class.getName());
}
}
#Service
#Profile("prod")
public class MyServiceProdImpl implements MyService {
private final Logger LOG = LoggerFactory.getLogger(MyServiceProdImpl.class);
#Override
public void doSomething() {
LOG.debug("Doing something in " + MyServiceProdImpl.class.getName());
}
}
However, I'm getting the following error:
No qualifying bean of type [com.example.profileservice.MyService] found for dependency.
What am I missing?
UPDATE 1:
I'm manually setting the active profile during web application initialization, but I'm still getting the "No qualifying bean found" error. Changes can be seen here: https://github.com/overattribution/spring-profile-test/commit/09175a10b28ea8e5a08b43ad1416431bcf094c9d

Ok I got it to work. Profiles need to be set within the root context (as opposed to servlet context) during web application initialization. I have done so in my WebAppInitializer class like so:
https://github.com/overattribution/spring-profile-test/blob/f895a8bc67dc1f6ba2fcedb58b73a19cc5cf8cf7/src/main/java/com/example/config/WebAppInitializer.java
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
/**
* Overriding to include setting active profile.
*/
#Override
protected WebApplicationContext createRootApplicationContext() {
Class<?>[] configClasses = getRootConfigClasses();
if (!ObjectUtils.isEmpty(configClasses)) {
AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext();
String[] activeProfiles = getActiveProfiles();
rootAppContext.getEnvironment().setActiveProfiles(activeProfiles);
rootAppContext.register(configClasses);
return rootAppContext;
}
else {
return null;
}
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] {
ApplicationConfig.class
};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] {
WebMvcConfig.class
};
}
#Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
return new Filter[] {characterEncodingFilter};
}
protected String[] getActiveProfiles() {
PropertySource propertySource = null;
try {
propertySource = new ResourcePropertySource("classpath:application.properties");
String profilesString = (String) propertySource.getProperty(AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME);
return profilesString.split(",");
} catch (IOException e) {
throw new ResourceAccessException("application.properties is not available on the classpath");
}
}
}

A profile is a named logical grouping that may be activated programmatically via ConfigurableEnvironment.setActiveProfiles(java.lang.String...) or declaratively through setting the spring.profiles.active property, usually through JVM system properties, as an environment variable, or for web applications as a Servlet context parameter in web.xml.
I would say that it is not possible to specify active profile as a property within your properties file unless you use Spring Boot that also enables you to set the active profile in application.properties file.
Try to use one of the options above.

Related

Injecting spring bean (service layer class) into ResourceBundle

I created a class using ResourceBundle interface as shown below. This class is dependent on another class. The implementation class for ResourceBundle (QuestionnaireSource as shown below) always has null as dependencies. No matter if I use setter or constructor injection.
Could someone please help me with this issue. I am I missing some configuration here.
#Component
public class QuestionnaireSource extends ResourceBundle {
private final QuestionnaireCache questionnaireCache;
private static final Object lockObject = new Object();
#Override
protected Object handleGetObject(String key) {
// Gets an object for the given key from this resource bundle.
// Returns null if this resource bundle does not contain an object for the given key 0
Object value = null;
try {
value = getString(key, LocaleContextHolder.getLocale());
} catch (Exception ignored) {
}
return value;
}
public Questionnaire getString(String key, Locale locale) {
Locale l = safeLocale(locale);
return getResources(l).get(key);
}
private Locale safeLocale(Locale l) {
if (l.getLanguage().equalsIgnoreCase("DE")) {
return Locale.GERMAN;
} else {
return Locale.ENGLISH;
}
}
protected Map<String, Questionnaire> getResources(Locale locale) {
synchronized (lockObject) {
return questionnaireCache.getQuestionnaireCache().get(locale.getLanguage().toUpperCase());
}
}
#Override
public Enumeration<String> getKeys() {
return null;
}
public QuestionnaireSource(QuestionnaireCache questionnaireCache) {
super();
this.questionnaireCache = questionnaireCache;
}
}
Update:
I found that even simple dependency injection in resourceBundle is failing.
UPdate2:
The way I am using in the main class is as follows:
// ResourceBundle test here
System.out.println("Test here for resource bundle");
Locale locale = new Locale("de", "DE");
ResourceBundle bundle = ResourceBundle.getBundle("com.app.util.QuestionnaireSource", locale);
System.out.println(bundle.getString("some.test.string"));
Update3
I am writing a simple example to convey the scenario:
Some service class
#Service
public class SomeServiceTest {
public String testMethod(){
return "test here and complete";
}
}
Some example implementation of resource bundle
#Component
public class MyResourceBundle extends ResourceBundle {
private final SomeServiceTest someServiceTest;
#Autowired
public MyResourceBundle(SomeServiceTest someServiceTest) {
this.someServiceTest = someServiceTest;
}
#Override
protected Object handleGetObject(String key) {
if(key.equals("test"))
return "test";
return null;
}
#Override
public Enumeration<String> getKeys() {
return null;
}
}
Main.java
main(){
// ResourceBundle test here
System.out.println("Test here for resource bundle");
Locale locale = new Locale("de", "DE");
ResourceBundle bundle = ResourceBundle.getBundle("com.app.util.MyResourceBundle", locale);
System.out.println(bundle.getString("test"));
}
Update4:
I changed the annotation on classes as mentioned by on this post https://www.baeldung.com/spring-inject-bean-into-unmanaged-objects
but still I have the null dependency injection for SomeServiceTest class. The changes are as shown below.
SomeServiceTest.java
#Service
public class SomeServiceTest {
public String testMethod(){
return "test here and complete";
}
}
MyResourceBundle.java
#Configurable
public class MyResourceBundle extends ResourceBundle {
#Autowired
private SomeServiceTest someServiceTest;
public MyResourceBundle() {
}
#Override
protected Object handleGetObject(String key) {
if(key.equals("test"))
return someServiceTest.testMethod();
return null;
}
#Override
public Enumeration<String> getKeys() {
return null;
}
}
still SomeServiceTest class is null.
Can you please post an example on how you are using this class? Is it you (your code) or spring who instanciate it (on startup)?
#Component only works for beans which Spring instanciate. If you want to inject stuff in classes you instanciate in you code you can annotate the class with #Configurable.
Please see https://www.baeldung.com/spring-inject-bean-into-unmanaged-objects for some examples.
Make sure you have initialized the spring context
If you are using spring boot
You can get the application context after it starts and use it to get the bean you want
For example
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(YouApplication.class, args);
MyResourceBundle resConfig = run.getBean("myResourceBundle", MyResourceBundle .class);
resConfig.handleGetObject("test");
}
Unfortunately ResourceBundle.getBundle does not initialize the spring application context

Require a service to be active before a bundle is started

I have written a BundleActivator which should update certain configurations before its bundle starts. I need the ConfigurationAdmin service, but I get a null ServiceReference from the BundleContext in the start method of the BundleActivator.
The BundleActivator extends following abstract class and only implements the specific update logic:
public abstract class AbstractConfigUpdater implements BundleActivator {
private ServiceReference<ConfigurationAdmin> configurationAdminServiceReference;
#Override
public void start(final BundleContext context) throws Exception {
configurationAdminServiceReference = context.getServiceReference(ConfigurationAdmin.class);
final ConfigurationAdmin configurationAdmin = context.getService(configurationAdminServiceReference);
final Configuration[] configurations =
configurationAdmin.listConfigurations(getFilter());
if (configurations != null) {
for (final Configuration configuration : configurations) {
final Dictionary<String, Object> properties = configuration.getProperties();
if (updateProperties(properties)) {
configuration.update(properties);
}
}
}
}
protected abstract String getFilter();
/**
* Updates the properties if needed.
*
* #param properties
* the configuration properties
* #return if any modifications to the Dictionary were made
*/
protected abstract boolean updateProperties(final Dictionary<String, Object> properties);
#Override
public void stop(final BundleContext context) throws Exception {
context.ungetService(configurationAdminServiceReference);
}
}
I have added an annotation to the concrete BundleActivator to generate a manifest header to require the ConfigurationAdmin service to be available to the bundle:
#RequireCapability(filter = "(objectClass=org.osgi.service.cm.ConfigurationAdmin)",
ns = "osgi.service",
resolution = Resolution.mandatory)
The manifest header is generated, but I still get a null ServiceReference. How should I fix this? Or is there an alternative approach I could take to update configurations before their components are started?
I don't know if this could help, but you can develop a org.osgi.service.cm.ConfigurationPlugin to intercept all the properties that are injected at runtime and modify them:
public class MyConfigurationPlugin implements BundleActivator, ConfigurationPlugin {
ServiceRegistration<ConfigurationPlugin> configPluginRef;
#Override
public void start(BundleContext context) throws Exception {
//... init the config plugin
Map<String,String> properties = new HashMap<>();
configPluginRef = context.registerService(
ConfigurationPlugin.class,
this,
new Hashtable<>(properties));
}
#Override
public void modifyConfiguration(ServiceReference<?> reference,
Dictionary<String, Object> properties) {
/*
* View and possibly modify a set of configuration properties
* before they are sent to the Managed Service or the Managed Service Factory.
*/
}
}
Of course the Declarative Service approach is a way far simpler option:
#Component (
service= {},
configurationPid={
configPid1,
configPid2,
...
})
public class MyComponent {
#Activate
public void activate(BundleContext context, Map<String, String> properties) {
}
#Modified
public void updated(BundleContext context, Map<String, String> properties) {
// Called when properties change
}
}
but in this case you cannot alter properties values: you can only react to properties changes.
You can use OSGi ServiceTracker to wait and retrieve the service from the service registry.
For example,
import org.osgi.framework.Constants
import org.osgi.framework.Filter;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.service.cm.ConfigurationAdmin;
...
private static final long TIMEOUT_MILLIS = 10000;
#Override
public void start(final BundleContext context) throws Exception {
Filter filter = context.createFilter("(" + Constants.OBJECTCLASS + "=org.osgi.service.cm.ConfigurationAdmin)");
ServiceTracker<?, ?> configurationAdminTracker = new ServiceTracker<>(context, filter, null);
configurationAdminTracker.open();
ConfigurationAdmin configurationAdmin = (ConfigurationAdmin) configurationAdminTracker.waitForService(TIMEOUT_MILLIS);
configurationAdminTracker.close();
if (configurationAdmin == null) {
// Not found
}
...
}

Spring Boot Apache Camel Routes testing

I have a Springboot application, where I have some Camel routes configured.
public class CamelConfig {
private static final Logger LOG = LoggerFactory.getLogger(CamelConfig.class);
#Value("${activemq.broker.url:tcp://localhost:61616}")
String brokerUrl;
#Value("${activemq.broker.maxconnections:1}")
int maxConnections;
#Bean
ConnectionFactory jmsConnectionFactory() {
PooledConnectionFactory pooledConnectionFactory = new PooledConnectionFactory(new ActiveMQConnectionFactory(brokerUrl));
pooledConnectionFactory.setMaxConnections(maxConnections);
return pooledConnectionFactory;
}
#Bean
public RoutesBuilder route() {
LOG.info("Initializing camel routes......................");
return new SpringRouteBuilder() {
#Override
public void configure() throws Exception {
from("activemq:testQueue")
.to("bean:queueEventHandler?method=handleQueueEvent");
}
};
}
}
I want to test this route from activemq:testQueue to queueEventHandler::handleQueueEvent.
I tried different things mentioned here http://camel.apache.org/camel-test.html, but doesn't seem to get it working.
I am trying to do something like this:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {CamelConfig.class, CamelTestContextBootstrapper.class})
public class CamelRouteConfigTest {
#Produce(uri = "activemq:testQueue")
protected ProducerTemplate template;
#Test
public void testSendMatchingMessage() throws Exception {
template.sendBodyAndHeader("testJson", "foo", "bar");
// Verify handleQueueEvent(...) method is called on bean queueEventHandler by mocking
}
But my ProducerTemplate is always null. I tried auto-wiring CamelContext, for which I get an exception saying it cannot resolve camelContext. But that can be resolved by adding SpringCamelContext.class to #SpringBootTest classes. But my ProducerTemplate is still null.
Please suggest. I am using Camel 2.18 and Spring Boot 1.4.
In Camel 2.22.0 and ongoing, which supports Spring Boot 2 you can use the following template to test your routes with Spring Boot 2 support:
#RunWith(CamelSpringRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.NONE, classes = {
Route1.class,
Route2.class,
...
})
#EnableAutoConfiguration
#DisableJmx
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
public class RouteTest {
#TestConfiguration
static class Config {
#Bean
CamelContextConfiguration contextConfiguration() {
return new CamelContextConfiguration() {
#Override
public void beforeApplicationStart(CamelContext camelContext) {
// configure Camel here
}
#Override
public void afterApplicationStart(CamelContext camelContext) {
// Start your manual routes here
}
};
}
#Bean
RouteBuilder routeBuilder() {
return new RouteBuilder() {
#Override
public void configure() {
from("direct:someEndpoint").to("mock:done");
}
};
}
// further beans ...
}
#Produce(uri = "direct:start")
private ProducerTemplate template;
#EndpointInject(uri = "mock:done")
private MockEndpoint mockDone;
#Test
public void testCamelRoute() throws Exception {
mockDone.expectedMessageCount(1);
Map<String, Object> headers = new HashMap<>();
...
template.sendBodyAndHeaders("test", headers);
mockDone.assertIsSatisfied();
}
}
Spring Boot distinguishes between #Configuration and #TestConfiguration. The primer one will replace any existing configuration, if annotated on a top-level class, while #TestConfiguration will be run in addition to the other configurations.
Further, in larger projects you might run into auto-configuration issues as you can't rely on Spring Boot 2 to configure your custom database pooling or what not correctly or in cases where you have a specific directory structure and the configurations are not located within a direct ancestor directory. In that case it is proabably preferable to omit the #EnableAutoConfiguration annotation. In order to tell Spring to still auto-configure Camel you can simply pass CamelAutoConfiguration.class to the classes mentioned in #SpringBootTest
#SpringBootTest(webEnvironment = WebEnvironment.NONE, classes = {
Route1.class,
Route2.class,
RouteTest.Config.class,
CamelAutoConfiguration.class
}
As no automatic configuration is performed, Spring won't load the test configuration inside your test class nor initialize Camel as well. By adding those configs to the boot classes manually Spring will do it for you.
For one route with MQ and Spring Boot like this:
#Component
public class InboundRoute extends RouteBuilder {
#Override
public void configure() {
JaxbDataFormat personDataFormat = new JaxbDataFormat();
personDataFormat.setContextPath(Person.class.getPackage().getName());
personDataFormat.setPrettyPrint(true);
from("direct:start").id("InboundRoute")
.log("inbound route")
.marshal(personDataFormat)
.to("log:com.company.app?showAll=true&multiline=true")
.convertBodyTo(String.class)
.inOnly("mq:q.empi.deim.in")
.transform(constant("DONE"));
}
}
I use adviceWith in order to replace the endpoint and use only mocks:
#RunWith(CamelSpringBootRunner.class)
#UseAdviceWith
#SpringBootTest(classes = InboundApp.class)
#MockEndpoints("mock:a")
public class InboundRouteCamelTest {
#EndpointInject(uri = "mock:a")
private MockEndpoint mock;
#Produce(uri = "direct:start")
private ProducerTemplate template;
#Autowired
private CamelContext context;
#Test
public void whenInboundRouteIsCalled_thenSuccess() throws Exception {
mock.expectedMinimumMessageCount(1);
RouteDefinition route = context.getRouteDefinition("InboundRoute");
route.adviceWith(context, new AdviceWithRouteBuilder() {
#Override
public void configure() {
weaveByToUri("mq:q.empi.deim.in").replace().to("mock:a");
}
});
context.start();
String response = (String) template.requestBodyAndHeader("direct:start",
getSampleMessage("/SimplePatient.xml"), Exchange.CONTENT_TYPE, MediaType.APPLICATION_XML);
assertThat(response).isEqualTo("DONE");
mock.assertIsSatisfied();
}
private String getSampleMessage(String filename) throws Exception {
return IOUtils
.toString(this.getClass().getResourceAsStream(filename), StandardCharsets.UTF_8.name());
}
}
I use the following dependencies: Spring Boot 2.1.4-RELEASE and Camel 2.23.2. The complete source code is available on Github.
This is how I did this finally:
#RunWith(SpringRunner.class)
public class CamelRouteConfigTest extends CamelTestSupport {
private static final Logger LOG = LoggerFactory.getLogger(CamelRouteConfigTest.class);
private static BrokerService brokerSvc = new BrokerService();
#Mock
private QueueEventHandler queueEventHandler;
#BeforeClass
// Sets up an embedded broker
public static void setUpBroker() throws Exception {
brokerSvc.setBrokerName("TestBroker");
brokerSvc.addConnector("tcp://localhost:61616");
brokerSvc.setPersistent(false);
brokerSvc.setUseJmx(false);
brokerSvc.start();
}
#Override
protected RoutesBuilder createRouteBuilder() throws Exception {
return new CamelConfig().route();
}
// properties in .yml has to be loaded manually. Not sure of .properties file
#Override
protected Properties useOverridePropertiesWithPropertiesComponent() {
YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
try {
PropertySource<?> applicationYamlPropertySource = loader.load(
"properties", new ClassPathResource("application.yml"),null);// null indicated common properties for all profiles.
Map source = ((MapPropertySource) applicationYamlPropertySource).getSource();
Properties properties = new Properties();
properties.putAll(source);
return properties;
} catch (IOException e) {
LOG.error("application.yml file cannot be found.");
}
return null;
}
#Override
protected JndiRegistry createRegistry() throws Exception {
JndiRegistry jndi = super.createRegistry();
MockitoAnnotations.initMocks(this);
jndi.bind("queueEventHandler", queueEventHandler);
return jndi;
}
#Test
// Sleeping for a few seconds is necessary, because this line template.sendBody runs in a different thread and
// CamelTest takes a few seconds to do the routing.
public void testRoute() throws InterruptedException {
template.sendBody("activemq:productpushevent", "HelloWorld!");
Thread.sleep(2000);
verify(queueEventHandler, times(1)).handleQueueEvent(any());
}
#AfterClass
public static void shutDownBroker() throws Exception {
brokerSvc.stop();
}
}
Did you try using Camel test runner?
#RunWith(CamelSpringJUnit4ClassRunner.class)
If you are using camel-spring-boot dependency, you may know that it uses auto configuration to setup Camel:
CamelAutoConfiguration.java
It means that you may also need to add #EnableAutoConfiguration to your test.

Access Spring profiles in spring-junit test classes

I am using Spring 4.3.0.I am writing a SDK in that i am having the following classes,
Providers.java
#ComponentScan
#Service
//#PropertySource("classpath:application.properties")
public class Providers {
#Autowired
ApplicationContext context;
public Providers(){
}
public Providers(ApplicationContext applicationContext){
this.context = applicationContext;
}
//...Other SDK component code
}
ProvidersBuilder.java
public class ProvidersBuilder {
//Set providers property
public Providers build() throws LifecycleException, InsufficientPropertiesException {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext();
StandardEnvironment env = new StandardEnvironment();
context.setEnvironment(env);
if(cond1){
context.getEnvironment().addActiveProfile("profile1");
}
if(cond2){
context.getEnvironment().addActiveProfile("profile2");
}
...etc
context.setParent(null);
context.register(Providers.class);
context.refresh();
Providers Providers = new Providers(context);
return Providers;
}
}
I have following configuration for Spring-Junit test classes,
SpringContextLoader.java
#ComponentScan(basePackages = "com.providers.global")
#PropertySource("classpath:application.properties")
public class SpringContextLoader {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(SpringContextLoader.class);
}
}
In one of my test class, I am trying to print all the profiles,
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = SpringContextLoader.class)
public class ProvidersTest{
#Autowired
ApplicationContext context;
#Before
public void beforeMethod() throws Exception {
String[] profiles = context.getEnvironment().getActiveProfiles();
if(profiles != null && profiles.length > 0){
for (String string : profiles) {
logger.info(String.format("Active Profiles in test::%s",string));
}
}
}
#Test
public void activateProviders() throws Exception{
...invoking test call
}
}
In the logs i am able to see only the profiles configured in application.properties, but i would like to get the profiles which are dynamically added in ProvidersBuilder.java.
Basically i would run ProvidersTest only for particular profiles for that i am using the following annotation,
#IfProfileValue(name = "spring.profiles.active", values = { "charging" })
Since application context always returns default profile configured in application.properties this class never get a chance to run.
Could anyone please help me to resolve this issue.Why the profiles added in ProvidersBuilder.java is not available in ProvidersTest.java?
**Edit 1 **
SpringContextLoader.java
#ComponentScan(basePackages = "com.providers.global")
#PropertySource("classpath:application.properties")
public class SpringContextLoader {
#Bean(name = "ConfigApplicationContext")
public AnnotationConfigApplicationContext applicationContext() {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext();
return context;
}
}
Now we are not creating new AnnotationConfigApplicationContext anywhere in application.
ProvidersBuilder.java
public class ProvidersBuilder {
#Autowired
#Qualifier("ConfigApplicationContext")
public AnnotationConfigApplicationContext context;
//Set providers property
public Providers build() throws LifecycleException, InsufficientPropertiesException {
context.setEnvironment(env); **Here i am getting getting NullPointerException**
if(cond1){
context.getEnvironment().addActiveProfile("profile1");
}
if(cond2){
context.getEnvironment().addActiveProfile("profile2");
}
...etc
context.setParent(null);
context.register(Providers.class);
context.refresh();
Providers Providers = new Providers(context);
return Providers;
}
}
In the ProvidersBuilder.java while getting "AnnotationConfigApplicationContext context" using #Autowired it returns null.

Change main endpoint in Spring Data Rest (usind Spring Boot)

Im building a small application using Spring (Boot, Data, Data Rest).
I have some JpaRepositories that aumotatically are exported as Rest endpoints.
What i want to do is to change the base path from / to /api.
Now to list all people for example i do a GET to http://localhost:8080/people and i want the url to be http://localhost:8080/api/people.
I tried adding this config class but nothing happened (it seems that Spring Boot overrides this config):
public class SpringWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer{
#Override
protected Class<?>[] getRootConfigClasses()
{
return new Class<?>[] { Application.class};
}
#Override
protected Class<?>[] getServletConfigClasses()
{
return new Class<?>[] { RestExporterRestConfig.class, RepositoryRestMvcConfiguration.class };
}
#Override
protected String[] getServletMappings()
{
return new String[] { "/api/*" };
}
}
My Application.java:
#Configuration
#ComponentScan
#Import(RestExporterRestConfig.class)
#EnableJpaRepositories
#EnableAutoConfiguration
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
and RestExporterRestConfig:
#Configuration
public class RestExporterRestConfig extends RepositoryRestMvcConfiguration {
#Bean
public Validator validator() {
return new LocalValidatorFactoryBean();
}
#Override
protected void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener v) {
v.addValidator("beforeCreate", validator());
}
#Bean
#Qualifier
public DefaultFormattingConversionService defaultConversionService() {
DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
conversionService.addConverter(StringToDate.INSTANCE);
return conversionService;
}
#Bean
public DomainClassConverter<?> domainClassConverter() {
return new DomainClassConverter<DefaultFormattingConversionService>(defaultConversionService());
}
}
Well i figured it out. SpringWebAppInitializer is not necesary in this case. I just added this code to Application.java:
#Bean
public ServletRegistrationBean dispatcherRegistration(DispatcherServlet dispatcherServlet) {
ServletRegistrationBean reg = new ServletRegistrationBean(dispatcherServlet);
reg.addUrlMappings("/api/*");
return reg;
}
I think this is the correct way to modify (add, change mappings, etc) servlets using Spring Boot.

Resources