#Autowired does not work with my SOAP handler class. Throws a nullPointerException? - spring

This is my SOAP Handler class to generate security service handlers for a CRM. Everything was working fine as I hard coded my credentials - Username & Password. Now I tried to remove the hard-coding by defining the credentials in a properties file and autowiring it in this class. This method is not working and Spring throws a NullPointerExc (autowiring not happening I guess!) everytime I try to access my CRM. Why does #Autowired not work here while it works perfectly well my #Service, #Controller classes? Here is my code:
package com.myPortlet.crmService;
import java.util.Properties;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPFactory;
import javax.xml.soap.SOAPHeader;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class ECMClientHeaderHandler implements SOAPHandler<SOAPMessageContext> {
final static Logger logger = LoggerFactory
.getLogger(ECMClientHeaderHandler.class);
private static final String AUTH_NS = "http://schemas.xmlsoap.org/ws/2002/12/secext";
private static final String AUTH_PREFIX = "wss";
public ECMClientHeaderHandler() {
}
public boolean handleFault(SOAPMessageContext smc) {
return true;
}
public void close(MessageContext mc) {
}
#Autowired
private Properties applicationProperties;
public boolean handleMessage(SOAPMessageContext smc) {
boolean direction = ((Boolean) smc
.get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY))
.booleanValue();
String userName = applicationProperties.getProperty("myCRM.userName"); /*previously hard-coded*/
String password = applicationProperties.getProperty("myCRM.password"); /*previously hard-coded*/
logger.info("This is USERNAME:"+ userName);
logger.info("This is PASSWORD:"+ password);
if (direction) {
try {
SOAPEnvelope envelope = smc.getMessage().getSOAPPart()
.getEnvelope();
SOAPFactory soapFactory = SOAPFactory.newInstance();
// WSSecurity <Security> header
SOAPElement wsSecHeaderElm = soapFactory.createElement(
"Security", AUTH_PREFIX, AUTH_NS);
SOAPElement userNameTokenElm = soapFactory.createElement(
"UsernameToken", AUTH_PREFIX, AUTH_NS);
SOAPElement userNameElm = soapFactory.createElement("Username",
AUTH_PREFIX, AUTH_NS);
userNameElm.addTextNode(userName);
SOAPElement passwdElm = soapFactory.createElement("Password",
AUTH_PREFIX, AUTH_NS);
passwdElm.addTextNode(password);
userNameTokenElm.addChildElement(userNameElm);
userNameTokenElm.addChildElement(passwdElm);
// add child elements to the root element
wsSecHeaderElm.addChildElement(userNameTokenElm);
// create SOAPHeader instance for SOAP envelope
SOAPHeader sh;
if(envelope.getHeader()==null){
logger.info("SOAPHeader null.Add header");
sh = envelope.addHeader();
}else{
logger.info("SOAPHeader already present");
sh = envelope.getHeader();
}
// add SOAP element for header to SOAP header object
sh.addChildElement(wsSecHeaderElm);
} catch (Exception ex) {
ex.printStackTrace();
throw new RuntimeException(ex);
}
}
return true;
}
public java.util.Set<QName> getHeaders() {
return null;
}
}
The "myCRM.userName" & "myCRM.password" is defined in my application.properties file. And the classPath of application.properties is defined in applicationContext.xml:
<util:properties id="applicationProperties" location="classpath:/i18n/application.properties"/>
What is going wrong?

The Spring Context has to be made aware that it needs to load some autowired components on a specific class. The #Controller annotation and a reference in the spring-servlet.xml ensure just that.
You can try adding this to your spring-servlet.xml
<context:component-scan base-package="com.myPortlet.crmService" />
Also Add a #Controller annotation in your class to initiate auto wiring at server startup. Else your Properties instance will be null everytime you try to access it.

I had a similar problem trying injecting a dependency in my #webservice class. I solved it adding the method below in the class (org.springframework.web.context.support.SpringBeanAutowiringSupport;)
#PostConstruct
#WebMethod(exclude = true)
public void init() {
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}

Related

Spring Cloud Gateway : actuator refresh does not reload properties

I am actually working on a project with Spring Cloud Gateway.
I have a Configuration class which gets its Properties from a custom PropretySourceFactory. I want to make a hot reload of the properties so I call actuator/refresh (curl localhost:8080/actuator/refresh -d {}H "Content-Type: application/json") but it does not reload my configuration properties. No error or exceptions.
Here is the Configuration class:
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
#Configuration
#ConfigurationProperties
#PropertySource(value="", factory=NatsPropertySourceFactory.class)
public class NatsConfiguration {
private String apiKey;
private String apiKeyConsumer;
private String apiKeyValidity;
private String apiKeyCreation;
private int ratelimitMaxTokens;
private int ratelimitReplenishFrequency;
private int ratelimitReplenishRate;
// Getters and setter
//...
}
value is empty on PropertySource because I will not get my configuration from a file but from a message queue.
and the NatsPropertySourceFactory:
public class NatsPropertySourceFactory implements PropertySourceFactory{
final private NatsConfigurationService natsConfigurationService = new NatsConfigurationServiceImpl();
#Override
public PropertySource<?> createPropertySource(String arg0, EncodedResource arg1) throws IOException {
MapPropertySource result = null;
Logger log = LoggerFactory.getLogger(this.getClass());
try {
result = new MapPropertySource("nats", natsConfigurationService.getConfiguration());
} catch (ConfigurationException e) {
log.error("RECUPERATION DE CONFIGURATION DEPUIS NATS EN ERREUR", e);
System.exit(1);
}
return result;
}
}
My properties are not used with #Value, so I should not need #RefreshScope.
When I call /actuator/refresh the NatsConfiguration class is not recreated.
For information I use webflux with SpringSecurity (actuator urls are permitAll: pathMatchers("/actuator/**").permitAll())
#EnableWebFluxSecurity
#EnableWebFlux
public class SecurityConfiguration implements WebFluxConfigurer {
Where am I wrong?
By the way, I found the exact behaviour of /actuator/refresh: it reinstanciates the #Configuration class but does nothing for the PropertySourceFactory.
I have found a workaround: I created a REST Controler which calls the createPropertySource method of the PropertySourceFactory and then calls the /actuator/refresh url. It does exactly what I wanted: the #Configuration class is up to date with the new properties given by the PropertySourceFactory.

Why does Spring boot returns 404 error, but works if I place all methods of all controllers under one controller class?

I get 404 error when I try to send a request to access handleFileUpload( ) method
But if I place handleFileUpload( ) in DetailsController.java things work. Why is that? I'm using Spring boot.
I have two controller classes.
I don't have ServletInitializer.java
com.amazon.s3
|__ AmazonS3Controller.java
com.myproject
|__ DetailsController.java
This is how my #SpringBootApplication class looks like
#SpringBootApplication //This annotation means, it is the starting point of the app.
public class QqdApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(QqdApplication.class, args);
}
DetailsController.java
#RestController
#Component
public class DetailsController {
#Autowired
private DetailsService detailsService;
#RequestMapping("/contactUs")
public ModelAndView contactUs(){
ModelAndView mav = new ModelAndView();
mav.setViewName("contactUs");
return mav;
}
}
AmazonS3Controller.java
package com.amazon.s3;
import com.amazon.s3.AmazonS3Template;
import com.amazonaws.services.s3.model.*;
import java.util.List;
import java.util.stream.Collectors;
import javax.servlet.annotation.MultipartConfig;
#RestController
#RequestMapping("/s")
public class AmazonS3Controller {
private AmazonS3Template amazonS3Template;
private String bucketName;
#Autowired
public AmazonS3Controller(AmazonS3Template amazonS3Template, #Value("${amazon.s3.default-bucket}") String bucketName) {
this.amazonS3Template = amazonS3Template;
this.bucketName = bucketName;
}
#PostMapping(value = "upload", headers = "Accept=*/*")
#ResponseBody
public String handleFileUpload() {
JSONObject result = new JSONObject();
try {
// System.out.println("we ar ehere" + file.getName() + " " + file.getContentType() + " " + file.getSize());
result.put("link", "https://static.swappa.com/static/icons/stars/star-on-small-green.png");
System.out.println("imgae returned");
} catch (JSONException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
return new JSONArray().put(result).toString();
}
}
My application.properties looks like
spring.mvc.view.prefix: /WEB-INF/jsp/
spring.mvc.view.suffix: .jsp
#AWS details
amazon.s3.default-bucket=<someVal>
#Database
spring.datasource.....=....
#Hibernate
entitymanager.packagesToScan:com
spring.jpa.....=....
PS: Ok, After renaming the com.amazon.s3 to com.myproject.s3 things are working. But, I still don't get why it wasn't working before and why its working now.
P.S.S: I typed the above three lines here rather than comment, because SOF keep on telling me that there was too much code and less text. Sorry I cannot write stories here. I feel I gave enough details. Thanks.
The annotation #SpringBootApplication includes #ComponentScan:
The #SpringBootApplication annotation is equivalent to using
#Configuration, #EnableAutoConfiguration and #ComponentScan with their
default attributes:
https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-using-springbootapplication-annotation.html
#ComponentScan will, by default, scan for annotations from the package of the class the annotation is residing on ( i.e. the package of QqdApplication)
If specific packages are not defined, scanning will occur from the
package of the class that declares this annotation.
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/ComponentScan.html
So the #PostMapping annotation was not being captured when placed in a controller in the package com.amazon.s3 to com.myproject.s3. Either you had to change the package to be under a scanned location, or you had to specify which packages to scan in the #ComponentScan annotation.

Autowire working in unit test but not in main java class

I've a domain class that I want to auto-populate from external config. Here is my domain class:
#Data
#Configuration
#PropertySource("classpath:application.properties")
public class StudioVo {
#Value("${studio.code}")
private code;
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
Here is my context xml:
<bean class="org.springframework.batch.core.scope.StepScope" />
<bean id="ItemReader" class="com.sdm.studio.reader.StudioReader" scope="step">
<property name="studioVo" ref="StudioVo" />
</bean>
<bean id="StudioConfigVo" class="com.sdm.studio.domain.StudioVo" />
</bean>
Here is the class where I want to use the vo:
#Slf4j
#Data
public class StudioReader implements ItemReader<List<Studio>> {
private StudioVo studioVo;
public List<Studio> read() throws Exception {
System.out.println("getCode: " + studioVo.getCode()); //code is null here
return null;
}
}
However when I run it via unit test by autowiring, it runs fine. Like this:
#RunWith(SpringRunner.class)
#SpringBootTest
public class StudioTest {
#Autowired
private StudioVo studioVo;
#Test
public void testAutoPopulationOfStudio(){
System.out.println("getCode: "+ studioVo.getCode()); // works!
// Assert.assertTrue(studioVo.getCode().equals("102"));
}
}
Not sure what's going on here - I'm working with an old Spring Batch application wrapped in Spring Boot (so there is a mix of XML based and Java based config - and may be that is the cause of this issue). What am I missing?
In your StudioTest, you are autowiring StudioReader where as you missed the #Autowired in your StudioReader code, so add it as shown below:
#Slf4j
#Data
public class StudioReader implements ItemReader<List<Studio>> {
#Autowired //add this so that studioVo can be injected
private StudioVo studioVo;
//add other code
}
Please be certain to note that using #Autowire requires a chain of Spring-managed beans below it from wherever you are using it including the class in which you are using #Autowire. That is because Spring needs the precedent references to match up the object-reference hierarchy. I.e., in business logic layer ClassA, you want to #Autowire a field. ClassA itself needs to be a managed bean. Further, if the field you want to #Autowire holds an object that has referential dependencies to other objects (and most do), these also must be Spring-managed.
For example, the following will work:
package com.example.demo;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MessageRunner {
private static SetterMessage setterMessage;
public static void main(String[] args) {
setterMessage = (SetterMessage) (new AnnotationConfigApplicationContext(DemoConfiguration.class)).getBean("setterMessage");
setterMessage.setMessage("Finally it works.");
p(setterMessage.getMessage());
}
private static void p(String s) {
System.out.println(s);
}
}
DemoConfiguration.java looks like this:
package com.example.demo;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
#Configuration
#ComponentScan(basePackages = "com.example.demo")
public class DemoConfiguration {
}
SetterMessage.java, this:
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
#Service
#Scope("prototype")
public class SetterMessage {
private String message = null;
#Autowired
private SetterMessage2 setterMessage2;
public String getMessage(){
return message+setterMessage2.getSubMessage();
}
public void setMessage(String message) {
this.message = message;
setterMessage2.setSubMessage("("+message+")");
}
}
SetterMessage2.java:
package com.example.demo;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
#Service
#Scope("prototype")
public class SetterMessage2 {
private String subMsg = "";
public void setSubMessage(String msg) {
subMsg = msg;
}
public String getSubMessage() {
return subMsg;
}
}
Note that SetterMessage2.java is annotated as a Component (#Service) but no field in it is autowired. That is because it's the end of the object reference chain. But because it is a Component, it can be autowired into SetterMessage.java. However look at MessageRunner.java's main() method and field declarations. Note that the class field SetterMessage is NOT autowired. If it were annotated as #Autowired, main() would fail at runtime, throwing an NPE with the reference to setterMessage in main(). This is because MessageRunner.java is not marked as some kind of component. So we need to grab a valid instance of MessageSetter from the application context and use it.
To emphasize, the following version of MessageRunner.java's main() method WILL FAIL, throwing an NPE, if MessageRunner.java looked like this:
...
public class MessageRunner {
#Autowired // <-- This will not do the job for us
private static SetterMessage setterMessage;
public static void main(String[] args) {
setterMessage.setMessage("Finally it works."); // NPE here on ref to setterMessage
p(setterMessage.getMessage());
}
...
This is a real gotchya for people new to Spring. In fact, I'd place it among the Top Five Spring Newbie Discouragers and a really evil, pernicious detail that has caused new Spring programmers countless hours in aggravation and Google searches. So I do hope that noting this phenom here will save at least some newbies time and high blood pressure spikes.
Note: If you go to create the above classes in your IDE, bear in mind these were developed with Spring Boot enabled.

Spring beans are not injected in flyway java based migration

I'm trying to inject component of configuration properties in the flyway migration java code but it always null.
I'm using spring boot with Flyway.
#Component
#ConfigurationProperties(prefix = "code")
public class CodesProp {
private String codePath;
}
Then inside Flyway migration code, trying to autowrire this component as following:
public class V1_4__Migrate_codes_metadata implements SpringJdbcMigration {
#Autowired
private CodesProp codesProp ;
public void migrate(JdbcTemplate jdbcTemplate) throws Exception {
codesProp.getCodePath();
}
Here, codesProp is always null.
Is there any way to inject spring beans inside flyway or make it initialized before flyway bean?
Thank You.
Flyway doesn't support dependency injection into SpringJdbcMigration implementations. It simply looks for classes on the classpath that implement SpringJdbcMigration and creates a new instance using the default constructor. This is performed in SpringJdbcMigrationResolver. When the migration is executed, SpringJdbcMigrationExecutor creates a new JdbcTemplate and then calls your migration implementation's migrate method.
If you really need dependencies to be injected into your Java-based migrations, I think you'll have to implement your own MigrationResolver that retrieves beans of a particular type from the application context and creates and returns a ResolvedMigration instance for each.
If like me, you don't want to wait for Flyway 4.1, you can use Flyway 4.0 and add the following to your Spring Boot application:
1) Create a ApplicationContextAwareSpringJdbcMigrationResolver class in your project:
import org.flywaydb.core.api.FlywayException;
import org.flywaydb.core.api.MigrationType;
import org.flywaydb.core.api.MigrationVersion;
import org.flywaydb.core.api.configuration.FlywayConfiguration;
import org.flywaydb.core.api.migration.MigrationChecksumProvider;
import org.flywaydb.core.api.migration.MigrationInfoProvider;
import org.flywaydb.core.api.migration.spring.SpringJdbcMigration;
import org.flywaydb.core.api.resolver.ResolvedMigration;
import org.flywaydb.core.internal.resolver.MigrationInfoHelper;
import org.flywaydb.core.internal.resolver.ResolvedMigrationComparator;
import org.flywaydb.core.internal.resolver.ResolvedMigrationImpl;
import org.flywaydb.core.internal.resolver.spring.SpringJdbcMigrationExecutor;
import org.flywaydb.core.internal.resolver.spring.SpringJdbcMigrationResolver;
import org.flywaydb.core.internal.util.ClassUtils;
import org.flywaydb.core.internal.util.Location;
import org.flywaydb.core.internal.util.Pair;
import org.flywaydb.core.internal.util.StringUtils;
import org.flywaydb.core.internal.util.scanner.Scanner;
import org.springframework.context.ApplicationContext;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
/**
* Migration resolver for {#link SpringJdbcMigration}s which are registered in the given {#link ApplicationContext}.
* This resolver provides the ability to use other beans registered in the {#link ApplicationContext} and reference
* them via Spring's dependency injection facility inside the {#link SpringJdbcMigration}s.
*/
public class ApplicationContextAwareSpringJdbcMigrationResolver extends SpringJdbcMigrationResolver {
private final ApplicationContext applicationContext;
public ApplicationContextAwareSpringJdbcMigrationResolver(Scanner scanner, Location location, FlywayConfiguration configuration, ApplicationContext applicationContext) {
super(scanner, location, configuration);
this.applicationContext = applicationContext;
}
#SuppressWarnings("unchecked")
#Override
public Collection<ResolvedMigration> resolveMigrations() {
// get all beans of type SpringJdbcMigration from the application context
Map<String, SpringJdbcMigration> springJdbcMigrationBeans =
(Map<String, SpringJdbcMigration>) this.applicationContext.getBeansOfType(SpringJdbcMigration.class);
ArrayList<ResolvedMigration> resolvedMigrations = new ArrayList<ResolvedMigration>();
// resolve the migration and populate it with the migration info
for (SpringJdbcMigration springJdbcMigrationBean : springJdbcMigrationBeans.values()) {
ResolvedMigrationImpl resolvedMigration = extractMigrationInfo(springJdbcMigrationBean);
resolvedMigration.setPhysicalLocation(ClassUtils.getLocationOnDisk(springJdbcMigrationBean.getClass()));
resolvedMigration.setExecutor(new SpringJdbcMigrationExecutor(springJdbcMigrationBean));
resolvedMigrations.add(resolvedMigration);
}
Collections.sort(resolvedMigrations, new ResolvedMigrationComparator());
return resolvedMigrations;
}
ResolvedMigrationImpl extractMigrationInfo(SpringJdbcMigration springJdbcMigration) {
Integer checksum = null;
if (springJdbcMigration instanceof MigrationChecksumProvider) {
MigrationChecksumProvider version = (MigrationChecksumProvider) springJdbcMigration;
checksum = version.getChecksum();
}
String description;
MigrationVersion version1;
if (springJdbcMigration instanceof MigrationInfoProvider) {
MigrationInfoProvider resolvedMigration = (MigrationInfoProvider) springJdbcMigration;
version1 = resolvedMigration.getVersion();
description = resolvedMigration.getDescription();
if (!StringUtils.hasText(description)) {
throw new FlywayException("Missing description for migration " + version1);
}
} else {
String resolvedMigration1 = ClassUtils.getShortName(springJdbcMigration.getClass());
if (!resolvedMigration1.startsWith("V") && !resolvedMigration1.startsWith("R")) {
throw new FlywayException("Invalid Jdbc migration class name: " + springJdbcMigration.getClass()
.getName() + " => ensure it starts with V or R," + " or implement org.flywaydb.core.api.migration.MigrationInfoProvider for non-default naming");
}
String prefix = resolvedMigration1.substring(0, 1);
Pair info = MigrationInfoHelper.extractVersionAndDescription(resolvedMigration1, prefix, "__", "");
version1 = (MigrationVersion) info.getLeft();
description = (String) info.getRight();
}
ResolvedMigrationImpl resolvedMigration2 = new ResolvedMigrationImpl();
resolvedMigration2.setVersion(version1);
resolvedMigration2.setDescription(description);
resolvedMigration2.setScript(springJdbcMigration.getClass().getName());
resolvedMigration2.setChecksum(checksum);
resolvedMigration2.setType(MigrationType.SPRING_JDBC);
return resolvedMigration2;
}
}
2) Add a new configuration class to post process the Spring Boot generated Flyway instance:
import org.flywaydb.core.Flyway;
import org.flywaydb.core.internal.dbsupport.DbSupport;
import org.flywaydb.core.internal.dbsupport.h2.H2DbSupport;
import org.flywaydb.core.internal.dbsupport.mysql.MySQLDbSupport;
import com.pegusapps.zebra.infrastructure.repository.flyway.ApplicationContextAwareSpringJdbcMigrationResolver;
import org.flywaydb.core.internal.resolver.sql.SqlMigrationResolver;
import org.flywaydb.core.internal.util.Location;
import org.flywaydb.core.internal.util.PlaceholderReplacer;
import org.flywaydb.core.internal.util.scanner.Scanner;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
import java.sql.SQLException;
#Configuration
#ComponentScan("db.migration")
public class FlywayConfiguration {
#Bean
public BeanPostProcessor postProcessFlyway(ApplicationContext context) {
return new BeanPostProcessor() {
#Override
public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
return o;
}
#Override
public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
if (o instanceof Flyway) {
Flyway flyway = (Flyway) o;
flyway.setSkipDefaultResolvers(true);
ApplicationContextAwareSpringJdbcMigrationResolver resolver = new ApplicationContextAwareSpringJdbcMigrationResolver(
new Scanner(Thread.currentThread().getContextClassLoader()),
new Location("classpath:db/migration"),
context.getBean(org.flywaydb.core.api.configuration.FlywayConfiguration.class),
context);
SqlMigrationResolver sqlMigrationResolver = null;
try {
sqlMigrationResolver = new SqlMigrationResolver(
getDbSupport(),
new Scanner(Thread.currentThread().getContextClassLoader()),
new Location("classpath:db/migration"),
PlaceholderReplacer.NO_PLACEHOLDERS,
"UTF-8",
"V",
"R",
"__",
".sql");
} catch (SQLException e) {
e.printStackTrace();
}
flyway.setResolvers(sqlMigrationResolver, resolver);
}
return o;
}
private DbSupport getDbSupport() throws SQLException {
DataSource dataSource = context.getBean(DataSource.class);
if( ((org.apache.tomcat.jdbc.pool.DataSource)dataSource).getDriverClassName().equals("org.h2.Driver"))
{
return new H2DbSupport(dataSource.getConnection());
}
else
{
return new MySQLDbSupport(dataSource.getConnection());
}
}
};
}
}
Note that I have some hardcoded dependencies on tomcat jdbc pool, h2 and mysql. If you are using something else, you will need to change the code there (If there is anybody that knows how to avoid it, please comment!)
Also note that the #ComponentScan package needs to match with where you will put the Java migration classes.
Also note that I had to add the SqlMigrationResolver back in since I want to support both the SQL and the Java flavor of the migrations.
3) Create a Java class in the db.migrations package that does the actual migration:
#Component
public class V2__add_default_surveys implements SpringJdbcMigration {
private final SurveyRepository surveyRepository;
#Autowired
public V2__add_surveys(SurveyRepository surveyRepository) {
this.surveyRepository = surveyRepository;
}
#Override
public void migrate(JdbcTemplate jdbcTemplate) throws Exception {
surveyRepository.save(...);
}
}
Note that you need to make the class a #Component and it needs to implement the SpringJdbcMigration. In this class, you can use Spring constructor injection for any Spring bean from your context you might need to do the migration(s).
Note: Be sure to disable ddl validation of Hibernate, because the validation seems to run before Flyway runs:
spring.jpa.hibernate.ddl-auto=none
In short do not autowire beans in your db migrations or even reference classes from your application!
If you refactor/delete/change classes you referenced in the migration it may not even compile or worse corrupt your migrations.
The overhead of using plain JDBC template for the migrations is not worth the risk.
If you are using deltaspike you can use BeanProvider to get a reference to your Class. Here is a DAO example, but it should work fine with your class too.
Change your DAO code:
public static UserDao getInstance() {
return BeanProvider.getContextualReference(UserDao.class, false, new DaoLiteral());
}
Then in your migration method:
UserDao userdao = UserDao.getInstance();
And there you've got your reference.
(referenced from: Flyway Migration with java)

#Autowired not working on jersey resource

workflowService is null. The bean configuration is correct because manual injection works fine in other portions of the application.
Here's my resource:
#Path("/workflowProcess")
#Consumes({MediaType.APPLICATION_JSON})
#Produces({MediaType.APPLICATION_JSON})
public class WorkflowProcessResource {
#Autowired
WorkflowService workflowService;
#Autowired
WorkflowProcessService workflowProcessService;
#GET
#Path ("/getWorkflowProcesses/{uuid}")
public Collection<WorkflowProcessEntity> getWorkflows (#PathParam("uuid") String uuid) {
WorkflowEntity workflowEntity = workflowService.findByUUID(uuid);
return workflowEntity.getWorkflowProcesses();
}
}
From what I keep finding on Google on sites like http://www.mkyong.com/webservices/jax-rs/jersey-spring-integration-example/, it looks like ContextLoaderListener is the key. But I've already added that to the application context.
import com.sun.jersey.spi.container.servlet.ServletContainer;
import com.sun.jersey.spi.spring.container.servlet.SpringServlet;
import org.atmosphere.cpr.AtmosphereFramework;
import org.atmosphere.cpr.AtmosphereServlet;
import org.atmosphere.handler.ReflectorServletProcessor;
import org.glassfish.grizzly.servlet.ServletRegistration;
import org.glassfish.grizzly.servlet.WebappContext;
import org.glassfish.grizzly.websockets.WebSocketAddOn;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.grizzly.http.server.NetworkListener;
import java.io.IOException;
import java.util.logging.Logger;
public class Main {
protected static final Logger logger = Logger.getLogger(Main.class.getName());
public static void main(String[] args) throws IOException {
logger.info("Starting server...");
final HttpServer server = HttpServer.createSimpleServer(".", 8181);
WebappContext ctx = new WebappContext("Socket", "/");
//enable annotation configuration
ctx.addContextInitParameter("contextClass", "org.springframework.web.context.support.AnnotationConfigWebApplicationContext");
ctx.addContextInitParameter("contextConfigLocation", "com.production");
//allow spring to do all of it's stuff
ctx.addListener("org.springframework.web.context.ContextLoaderListener");
//add jersey servlet support
ServletRegistration jerseyServletRegistration = ctx.addServlet("JerseyServlet", new SpringServlet());
jerseyServletRegistration.setInitParameter("com.sun.jersey.config.property.packages", "com.production.resource");
jerseyServletRegistration.setInitParameter("com.sun.jersey.spi.container.ContainerResponseFilters", "com.production.resource.ResponseCorsFilter");
jerseyServletRegistration.setInitParameter("com.sun.jersey.api.json.POJOMappingFeature", "true");
jerseyServletRegistration.setLoadOnStartup(1);
jerseyServletRegistration.addMapping("/api/*");
What you need here, I think, is #InjectParam instead of #Autowired
#InjectParam worked fine instead of #Autowired, with a slight change
#InjectParam cannot be applied to the constructor itself hence has to be applied to the arguments to the constructor.
public OrderService(#InjectParam OrderValidationService service,
#InjectParam OrderCampaignService campaignService) {
this.service = service;
this.submissionErrorHandler = submissionErrorHandler;
this.campaignService = campaignService;
}

Resources