I am developing a library with a Spring framework and adding as a dependent for different frameworks. Does Spring framework #Value annotation inside library work for different frameworks that take application properties from other frameworks and also from spring boot too? Or do I have to use pure Java with a resource bundle?
Spring-Boot library:
#EnableAutoConfiguration
#Configuration
public class ClientProperties {
#Value("${application.url:#{null}}")
public String baseApplicationUrl;
public static String application_url;
#Value("${application.username:#{null}}")
public String platformUsername;
public static String username;
#Value("${application.password:#{null}}")
public String platformPassword;
public static String password;
A client application using a different framework that is not spring. Application properties file as follow:
application.url="localhost"
application.username=test
application.password=test
Related
I have spring boot application which is referring to Framework jar( Framework jar are common library jar's which are required by all microservices )
In framework jar i have used #Value annotation to read the config.
#Value("${isxyzFeatureEnabled}")
private static String isFeatureEnabled;
This value is not getting set when the application starts. However if i move this class to Individual microservice then it works.
I need to keep this class in framework as it will be reused by many microservices.
Any suggestions how can i resolve this.
Your variable is static.
Unfortunately, "Spring doesn't support #Value on static fields."
Try this solution:
#RestController
public class PropertyController {
#Value("${name}")
private String name;
private static String NAME_STATIC;
#Value("${name}")
public void setNameStatic(String name){
PropertyController.NAME_STATIC = name;
}
}
More info about that: https://www.baeldung.com/spring-inject-static-field
I have a Spring Config class which I want to have it loaded when the application is running.
#Configuration
public class EventHubConfiguration {
#Bean
#ConfigurationProperties(...)
public EventHubClient someClient(final String namespace,
final String eventHubName,
final String sasKeyName,
final String sasKey) throws IOException, EventHubException {
ConnectionStringBuilder connStr = new ConnectionStringBuilder()
.setNamespaceName(namespace)
.setEventHubName(eventHubName)
.setSasKeyName(sasKeyName)
.setSasKey(sasKey);
return EventHubClient.createSync(connStr.toString(), Executors.newSingleThreadScheduledExecutor());
}
}
But how can I prevent it from loading when my integration tests are running. For example when I do mvn clean test or as part of my build. I don't wish the eventhub client to be created during my integration testing.
As i see in spring doc :
https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html#integration-testing
3.2.2. Dependency Injection of Test Fixtures
When the TestContext framework loads your application context, it can optionally configure instances of your test classes by using Dependency Injection. This provides a convenient mechanism for setting up test fixtures by using preconfigured beans from your application context.
So yes your test class must be a bean
I am working on a Spring-enabled embedded Tomcat application using annotation-based configuration. The application uses Spring MVC Controllers for its REST endpoints. As a separation of concerns, and to avoid having duplicate beans in separate contexts, the parent context contains all beans that are not REST endpoints, and the Spring Web MVC context contains all beans that are REST endpoints.
I want to write new and refactor old integration tests for these endpoints that are representative of the structure of the app. There are existing test classes like so:
import com.stuff.web.MyEndpoint;
#Configuration
#ComponentScan(basePackages = {"com.stuff"})
public class SpringConfig { ... }
#WebAppConfiguration
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {SpringConfig.class})
public class TestMyEndpoint {
#Autowired
private MyEndpoint myEndpoint;
private MockMvc mockMvc;
#Before
public void setUp() {
mockMvc = MockMvcBuilders
.standaloneSetup(myEndpoint)
.build();
}
#Test
public void testMyEndpoint() throws Exception {
mockMvc.perform(get("/myendpoint")
.accept(MediaType.APPLICATION_JSON_VALUE))
.andExpect(status().isOk())
.andReturn();
}
}
The problem is that the context that I am using for this test now has every bean loaded, whereas I would like to ensure that there are not non-REST beans loaded that call into RestController beans during the execution of the tests.
Adding something like
#Configuration
#ComponentScan(basePackages = {"com.stuff"},
excludeFilters = {
#Filter(type = FilterType.REGEX, pattern = "com.stuff.web.*")})
public class SpringConfig { ... }
Would ensure the kind of separation I'm going for, but then I don't have access to the com.stuff.web.MyEndpoint class that I'm trying to test.
Am I missing something easy? Let me know if I'm explaining the situation clearly.
The kind of separation you're describing (mvc vs non-mvc) made sense 10 years ago, not anymore. Separate your code by functionality/design patterns (web/service/repository etc), and have #Configuration classes specific to that layer. The Spring stereotype annotations are good enough hint how your app should be broken up. Then, put your tests in the same package as your target code, and mock/override any dependencies.
It doesn't appear you're using Spring Boot (you really should) but they have a great section in the docs for testing "slices" of your application.
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications-testing-autoconfigured-tests
Playing around with Spring Boot + MVC with static HTML pages, while noticed this thing:
Firstly, what I have:
Index controller:
#Controller
public class IndexController {
#RequestMapping("/")
public String index() {
return "index.html";
}
#RequestMapping("/{path:[^\\.]+}/**")
public String forward() {
return "forward:/";
}
}
The Html file is:...\src\main\resources\static\index.html
So when my main application class is:
#SpringBootApplication
public class MyApplication extends WebMvcConfigurerAdapter {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
Everything works well and in default path: localhost:8080\ I get index.html page content
But if I annotate Application class with #EnableWebMvc
#SpringBootApplication
#EnableWebMvc
public class MyApplication extends WebMvcConfigurerAdapter {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
I get exception: javax.servlet.ServletException: Could not resolve view with name 'index.html' in servlet with name 'dispatcherServlet'
But according to this spring doc it is a valid configuration.
Maybe someone can explain me why? Do I understand something wrong?
According to spring-boot's docs
The auto-configuration adds the following features on top of Spring’s defaults:
Static index.html support.
...
If you want to keep Spring Boot MVC features, and you just want to add
additional MVC configuration (interceptors, formatters, view
controllers etc.) you can add your own #Configuration class of type
WebMvcConfigurerAdapter, but without #EnableWebMvc. If you wish to
provide custom instances of RequestMappingHandlerMapping,
RequestMappingHandlerAdapter or ExceptionHandlerExceptionResolver you
can declare a WebMvcRegistrationsAdapter instance providing such
components.
So by adding #EnableWebMvc you just disable what spring-boot autoconfiguring for you. Namely static index.html support.
Actually I think when you choose to use spring boot you should use the default config of spring Boot. It means you just have to edit the file application.properties. Now if you use spring mvc, you have to provide your own servlet. So I think mixing up the to is not a good idea. Either you use spring Boot wiht no much config to do or you use spring mvc and you make all the necessary config.
According to Spring Boot MVC structure, you should locate your html file in the templates folder. Then will be visible for Spring Boot
src\main\resources\templates\index.html
Having experience with the Spring DI applicationContext.xml way of declaring Dependency Injection I now try to figure out how to do the same with Java EE6 CDI.
With Spring, I could ship my .jar with several configuration profiles like
unittest.xml, devel.xml, qa.xml, production.xml and activate them using command line parameters or environment variables.
With CDI, I could use #Alternative in beans.xml and properties in of web.xml but there seems no way of shipping multiple beans.xml for different environments.
I don't want to use Maven profiles/filters to produce 4-6 versions of my app although I understand that for some scenarios that would be the better solution (i.e. shipping ready build wars to customers - but I only use my wars internally so let's save compile time!)
Preferably, I would also be able to load those configuration files from the file system so that they could be edited by the sysadmins without having to re-build the app.
What is the Java EE6 way of having multiple configuration sets of dependencies and properties?
If there is none, what are the recommended alternatives as of 2013? Using Spring? Seam? Guice? I saw mentionings of Apache DeltaSpike but they still seem alpha juding from the web page.
I'd use a dynamic producer, using a Qualifier to identify the desired environment
// The qualifier for the production/qa/unit test
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE, ElementType.METHOD,
ElementType.FIELD, ElementType.PARAMETER})
public #interface Stage {
String value() default "production";
}
// The interface for the stage-dependant service
public interface Greeting{
public String sayHello();
}
// The production service
#Stage("production")
public class ProductionGreeting implements Greeting{
public String sayHello(){return "Hello customer"; }
}
// The QA service
#Stage("qa")
public class QAGreeting implements Greeting{
public String sayHello(){return "Hello tester"; }
}
// The common code wich uses the service
#Stateless
public class Salutation{
#Inject Greeting greeting;
public String sayHello(){ return greeting.sayHello(); };
}
// The dynamic producer
public class GreetingFactory{
#Inject
#Any
Instance<Greeting> greetings;
public String getEnvironment(){
return System.getProperty("deployenv");
}
#Produces
public Greeting getGreeting(){
Instance<Greeting> found=greetings.select(
new StageQualifier(getEnvironment()));
if (!found.isUnsatisfied() && !found.isAmbiguous()){
return found.get();
}
throw new RuntimeException("Error ...");
}
public static class StageQualifier
extends AnnotationLiteral<Stage>
implements Stage {
private String value;
public StageQualifier(String value){
this.value=value;
}
public String value() { return value; }
}
}
So here the container injects all available Greeting implementations into GreetingFactory, which in turn serves as #Producer for the intended one, basing the decision on the system property 'deployenv'.
The above answer by Carlo is good, we have all of this in DeltaSpike with the ProjectStage. Worth taking a look at so you don't have to write it all yourself.
An alternative solution is suggested by M.-Leander Reimer in his presentation Migrating a JSF-Based Web Application from Spring 3 to Java EE 7 and CDI (Slide 32), using a CDI extension:
#Alternative
#Stereotype
#Target({ElementType.TYPE, ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
public #interface ProfileAlternative {
Profile[] value();
}
public void processAnnotated(#Observes ProcessAnnotatedType<?> event) {
ProfileAlternative pa = getProfileAlternative(event);
if (profileAlternativeIsNotActive(pa)) {
event.veto();
}
}
He uses a custom annotation #ProfileAlternative mimicking Spring's #Profile and a CDI extension observing the ProcessAnnotatedType event to veto() the type if it is annotated with a profile and the profile is not active.