I've got a Maven project which uses Java-configured Spring (#Configuration etc.). Properties which are referenced by #Value are stored in different places, e.g. Tomcat's context.xml.
For testing I've created a .properties file to provide some values for the components and services. In my JUnit test (which uses a spring test context) this .properties file is added via #PropertySource. The problem is that the values will not be loaded from the file, instead the value identifier is set as value, e.g. ${someFlag:false} (so I get ClassCastExceptions for any other than String). Also the default value will not be set, so I think, the values won't be processed at all.
I'm sure Spring finds this file because when I change the value of #PropertySource I get some FileNotFoundException. Nevertheless I've tried different variants to point to this file an all have worked (tested by renaming which produced FileNotFoundException):
classpath:/test.properties (my preferred notation)
/test.properties
file:src/test/resources/test.properties
I'm also sure that Spring itself works, because when I remove the #Value, the class under test is injected via #Autowired in my test as expected.
Down below you'll find the problem scenario stripped down as much as possible. For versions and dependencies please see the pom.xml at the bottom.
MyService.java
package my.package.service;
// Imports
#Service
public class MyService {
#Value("${someFlag:false}")
private Boolean someFlag;
public boolean hasFlag() {
return BooleanUtils.isTrue(someFlag);
}
}
MyConfiguration.java
#Configuration
#ComponentScan(basePackages = {"my.package.service"})
public class MyConfiguration {
}
MyServiceComponentTest.java
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {MyTestConfiguration.class})
public class MyServiceComponentTest {
#Autowired
private MyService service;
#Test
public void hasFlagReturnsTrue() {
assertThat(service.hasFlag(), is(true));
}
}
MyTestConfiguration.java
#Configuration
#Import({MyConfiguration.class})
#PropertySource("classpath:/test.properties")
public class MyTestConfiguration {
}
src/test/resources/test.properties
someFlag=true
pom.xml
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>3.2.3.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Test dependencies -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
The issue here is you need a PropertySourcesPlaceholderConfigurer also which is actually responsible for resolving the ${..} fields, just add another bean which creates this bean:
#Bean
public static PropertySourcesPlaceholderConfigurer propertiesResolver() {
return new PropertySourcesPlaceholderConfigurer();
}
With Spring 4, it's now possible to use TestPropertySource:
#TestPropertySource(value="classpath:/config/test.properties")
In order to load specific properties for a junit test
In addition to Biju Kunjummen answer:
If you use #ConfigurationProperties to inject properties into bean setters, then ConfigurationPropertiesBindingPostProcessor need to be created (instead of PropertySourcesPlaceholderConfigurer):
#Configuration
static class PropertyConfig {
#Bean
public static ConfigurationPropertiesBindingPostProcessor propertiesProcessor() {
return new ConfigurationPropertiesBindingPostProcessor();
}
}
Related
I have created the below class under test folder to unit test the cassandra connection in my spring boot application
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest({ "spring.data.cassandra.port=9042",
"spring.data.cassandra.keyspace-name=keyspacename","spring.data.cassandra.concontact-points=url",
"spring.config.import=vaultpath"})
#EnableAutoConfiguration
#ContextConfiguration
#ComponentScan
#TestExecutionListeners({ CassandraUnitDependencyInjectionTestExecutionListener.class,
DependencyInjectionTestExecutionListener.class })
#CassandraUnit
public class ApplicationTests {
#Autowired
TestRepository testRepository;
#Test
public void contextLoads(){
System.out.println(test.findBytestId("***"));
}
}
Below are the dependencies added in pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-cassandra</artifactId>
</dependency>
<dependency>
<groupId>org.cassandraunit</groupId>
<artifactId>cassandra-unit-spring</artifactId>
<version>2.1.9.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
Getting the below error on trying to run the unit test not sure what other config needs to be added in test path
Expecting URI in variable: [cassandra.config]. Please prefix the file with file:/// for local files or file:/// for remote files. Aborting. If you are executing this from an external tool, it needs to set Config.setClientMode(true) to avoid loading configuration.
at org.cassandraunit.utils.EmbeddedCassandraServerHelper.copy(EmbeddedCassandraServerHelper.java:278)
at org.cassandraunit.utils.EmbeddedCassandraServerHelper.startEmbeddedCassandra(EmbeddedCassandraServerHelper.java:82)
at org.cassandraunit.utils.EmbeddedCassandraServerHelper.startEmbeddedCassandra(EmbeddedCassandraServerHelper.java:64)
Fatal configuration error; unable to start. See log for stacktrace.
I'm creating a web application using spring-boot with annotation based configuration.
At first, I created a spring application with annotation based config using Hibernate and JPA. It was working fine but then I needed to add spring-boot to my application and now cannot start it. Here is the code:
#SpringBootApplication
#EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
public class Runner {
public static void main(String[] args) {
SpringApplication.run(Runner.class, args);
}
}
#Configuration
#EnableTransactionManagement
#ComponentScans(value = { #ComponentScan("com.alex.pharm.dao"),
#ComponentScan("com.alex.pharm.service") })
public class AppConfig {
#Bean
public LocalEntityManagerFactoryBean geEntityManagerFactoryBean() {
LocalEntityManagerFactoryBean factoryBean = new LocalEntityManagerFactoryBean();
factoryBean.setPersistenceUnitName("LOCAL_PERSISTENCE");
return factoryBean;
}
#Bean
#ConditionalOnMissingBean(type = "JpaTransactionManager")
public JpaTransactionManager geJpaTransactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(geEntityManagerFactoryBean().getObject());
return transactionManager;
}
}
#RestController
public class HelloController {
#RequestMapping("/")
public String index() {
return "Greetings from Spring Boot!";
}
}
<groupId>com.sachatol.pharmacy</groupId>
<artifactId>pharmacyWebStore</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.1</version>
</dependency><!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.13</version>
</dependency>
<!-- Hibernate 5.2.9 Final -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.9.Final</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- Spring ORM -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<sourceDirectory>src/main/java</sourceDirectory>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
But when I try to run it I get the following exception:
ConfigServletWebServerApplicationContext : Exception encountered during context initialization
- cancelling refresh attempt:org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'requestMappingHandlerMapping'
defined in class path resource
[org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]:
Initialization of bean failed; nested exception is java.lang.NoSuchMethodError:
org.springframework.web.servlet.handler.AbstractHandlerMapping.obtainApplicationContext()
Lorg/springframework/context/ApplicationContext;
How can I fix it?
Issue found - I used the old version for spring-context in pom (4.3.7.RELEASE) which override the one that spring-boot has and was the reason of NoSuchMethodError. So spring-context dependency was old and obsolete after removing or changing it to newer version (5.0.3) application started fine
Your #RequestMapping seems missing some parts, try with something like that:
#RequestMapping(value = "/", method = RequestMethod.GET)
This also happens if you have two methods with same request mapping values. Make sure you have unique RequestMapping values.
In your request mapping, you have incorrectly used :
#RequestMapping("/")
Instead, use this mapping to specify the end-point and the request-method like this :
#RequestMapping(value = "/", method = RequestMethod.GET)
Hope it will solve your problem.
I am getting this exception while testing my Controller class
Caused by: java.lang.IllegalArgumentException: At least one JPA metamodel must be present!
at org.springframework.util.Assert.notEmpty(Assert.java:450)
at org.springframework.data.jpa.mapping.JpaMetamodelMappingContext.<init>(JpaMetamodelMappingContext.java:54)
at org.springframework.data.jpa.repository.config.JpaMetamodelMappingContextFactoryBean.createInstance(JpaMetamodelMappingContextFactoryBean.java:88)
at org.springframework.data.jpa.repository.config.JpaMetamodelMappingContextFactoryBean.createInstance(JpaMetamodelMappingContextFactoryBean.java:43)
at org.springframework.beans.factory.config.AbstractFactoryBean.afterPropertiesSet(AbstractFactoryBean.java:141)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1761)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1698)
My controller test class looks like this
#RunWith(SpringRunner.class)
#WebMvcTest(controllers = {SensorController.class}, secure = false)
public class SensorControllerTest {
#Autowired
private MockMvc mvc;
#MockBean
private SensorService sensorService;
.....
}
My Bootstrap class
#SpringBootApplication(scanBasePackages = "com.javadroider")
#RestController
#EntityScan("com.javadroider.notifier.commons.model")
#EnableJpaRepositories(basePackages = "com.javadroider.notifier")
public class NotifierApplication {
#GetMapping("/")
public String home(){
return "Welcome to Notifier";
}
public static void main(String[] args) {
SpringApplication.run(NotifierApplication.class, args);
}
}
My dependencies look like this
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
When I remove #EnableJpaRepositories from my Bootstrap class then controller test will be successful. But application will not start. It will fail with NoSuchBeanDefinitionException.
I am not sure if it is something related to the way I have configured my application. All my repository & model classes are in commons module and I am referring to them in my main aplpication.
My query is similar to https://github.com/spring-projects/spring-boot/issues/6844
IllegalArgumentException: At least one JPA metamodel must be present didn't solve my problem
The #WebMvcTest annotation does not auto configure any repositories or JPA layer beans for you because it is primarily focused on testing just the Controller level.
Your main class NotifierApplication is trying to do too much. See the single responsibility principle for good programming practices: https://en.wikipedia.org/wiki/Single_responsibility_principle
The main class should be used just to define your application it should not itself be a #RestController. Create a separate class, NotifierController, for example and make this your #RestController with your endpoints defined there:
#RestController
public class NotifierController {
#GetMapping("/")
public String home(){
return "Welcome to Notifier";
}
}
and keep this separate from your main class:
#SpringBootApplication(scanBasePackages = "com.javadroider")
#EntityScan("com.javadroider.notifier.commons.model")
#EnableJpaRepositories(basePackages = "com.javadroider.notifier")
public class NotifierApplication {
public static void main(String[] args) {
SpringApplication.run(NotifierApplication.class, args);
}
}
The reason it was failing the way you had it is that your WebMvcTest was trying to scan for JPA repositories and entities due to the annotations on the main class but this is not configured for WebMvcTests.
I am succesfully running EJB tests with Arquillian against an (older) Glassfish 3.1 embedded.
When trying to #Inject weld beans, I get a NPE when I want to address a method in a transitively injected Weld bean.
So, I am testing EJB A. EJB A has a ref to EJB B. EJB B has a ref to a Weld bean.
This is the Jar init.
#Deployment
public static Archive<?> createDeployment() {
return ShrinkWrap.create(JavaArchive.class, "itscool.jar")
.addClasses(DashboardService.class, PropertyService.class, StorageService.class, EPSRepository.class,
EmailService.class, NotificationRepository.class, EmailRepository.class, Configuration.class,
MailingList.class, BogusBean.class, Bogus.class)
.addAsManifestResource("META-INF/persistence.xml", "persistence.xml")
.addAsManifestResource(EmptyAsset.INSTANCE, "META-INF/beans.xml")
.addAsResource(new File("src/test/resources/csman.properties"), "csman.properties");
}
So, the injected bean is the Configuration.class. First, I thought there was some initialization error in the Configuration impl class, so I created the #Bogus and BogusBean to only test the injection. I get the same errors.
#Bogus
public class BogusBean {
public void setIt(){
}
}
And the Qualifier
#Documented
#Target({ ElementType.METHOD, ElementType.FIELD, ElementType.TYPE })
#Retention(RetentionPolicy.RUNTIME)
#Qualifier
public #interface Bogus {
}
And the injection in the EmailService (a #stateless session bean).
#Inject
#Bogus
private BogusBean bogus;
#EJB
private EmailRepository emailRepos;
#PostConstruct
public void init() {
bogus.setIt();
}
The NPE happens on the bogus.setIt() line. as bogus == null.
This is the maven config
<dependency>
<groupId>org.jboss.arquillian.junit</groupId>
<artifactId>arquillian-junit-container</artifactId>
<version>1.1.11.Final</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.core</groupId>
<artifactId>arquillian-core-api</artifactId>
<version>1.1.11.Final</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.weld.arquillian.container</groupId>
<artifactId>arquillian-weld-ee-embedded-1.1</artifactId>
<version>1.1.2.Final</version>
</dependency>
I added a Profile for the glassfish embedded
<profile>
<id>arquillian-glassfish-embedded</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<dependencies>
<dependency>
<groupId>org.jboss.arquillian.container</groupId>
<artifactId>arquillian-glassfish-embedded-3.1</artifactId>
<version>1.0.0.Final</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.main.extras</groupId>
<artifactId>glassfish-embedded-all</artifactId>
<version>3.1.2.2</version>
<!-- was 4.0 -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.23.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.23.2</version>
<scope>provided</scope>
</dependency>
</dependencies>
</profile>
I also tried to change from weld-ee to weld-se but then the container doesn't even start. (as stated here) : how-to-test-ejb-method-call-with-arquillian-weld-ee-embedded
I am trying to return a JSON object from a jax-rs but I get an internal server error whenever I try to access.
This is my method, I am using javax.ws.rs.GET.
#GET
#Produces("application/json")
public Testy getJson() {
return new Testy("hello");
}
This is the class:
public class Testy {
private final String value;
public Testy(String value){
this.value = value;
}
public String getValue(){
return value;
}
}
My Pom.xml has this dependency, I have tried various dependencies, but none work. There are various maven resources for jersey, there's jersey-client jersey-core.
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.3.3</version>
</dependency>
I am using Glassfish 4.
Questions about working with Jersey:
I have seen some places where they mention you need to have initialize POJO support, it seems like its for jersey 1.* but I am not sure. I don't need this if I am using 2.* ?
Do I have to modify the web.xml to point to the jersey servlet ?
How can I produce and consume JSON objects using POJO classes !?
Edit
Here is my auto generated config class.
I had to add the JacksonFeature resource to my ApplicationConfig Class.
#javax.ws.rs.ApplicationPath("webresources")
public class ApplicationConfig extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new java.util.HashSet<>();
addRestResourceClasses(resources);
resources.add(org.glassfish.jersey.jackson.JacksonFeature.class);
return resources;
}
/**
* Do not modify addRestResourceClasses() method.
* It is automatically populated with
* all resources defined in the project.
* If required, comment out calling this method in getClasses().
*/
private void addRestResourceClasses(Set<Class<?>> resources) {
resources.add(com.wfscorp.restapitwo.GenericResource.class);
}
}
Then everything worked!
Note
When I used the com.fasterxml.jackson.jaxrs dependency I was unable to deploy my application. I started getting a WELD-001408 Unsatisfied dependencies for type error so I had to exclude the jersey media multi part.
These are the dependencies in my pom.xml
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.13</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>2.7</version>
<scope>provided</scope>
</dependency>
</dependencies>
This will guide through the entire process Reference ,Simple and Easy - http://examples.javacodegeeks.com/enterprise-java/rest/jersey/json-example-with-jersey-jackson/
It may be that you need to expose the value property of your Testy object with a getter.