What does SpringClassRule/SpringMethodRule actually do? - spring-boot

In an integration test class I met these lines of code:
#ClassRule
public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();
#Rule
public final SpringMethodRule springMethodRule = new SpringMethodRule();
When I try to navigate to the class (I use Intellij Idea) I get 'Cannot find declaration to go to'. When I try to find usage I get 'No usage found in the project'
I am familiar with concept of Rules. But still don't understand what do these two things do.
I checked this page: https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/
no info there.

These aren't Spring Boot specific annotations, rather from the Spring Framework itself and allow use of Spring Contexts etc. without the use of the SpringRunner.
Javadoc, http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/test/context/junit4/rules/SpringClassRule.html
A concrete example can be found here,
http://eddumelendez.github.io/blog/2015/08/01/spring-4-2-0-springclassrule-and-springmethodrule/

Related

Trouble using a base Spock Specification and JenkinsRule with PluginManager

I want to use different sets of plugins for different Spock Specifications that extend an abstract BaseSpecification. I am having trouble doing that. From what I read, the #WithPlugin annotation didn't quite seem like what I need. So I've been trying to use JenkinsRule.with(PluginManager).
I'm using the Groovy Spock framework and v2.59 of the Jenkins Unit Test Harness org.jenkins-ci.main:jenkins-test-harness:2.59 to test Jenkins Job DSL that we've written to automate the initialization of our Jenkins instances.
I have a BaseSpecification class where I declare a field #Shared #ClassRule jenkinsRule = new JenkinsRule(). As I understand it, the JenkinsRule is how we interact with the Jenkins Unit Test Harness and the embedded Jenkins instances. This has worked fine in the past for all Specifications that extend BaseSpecification and define their own feature methods.
But when I try to use something like #Shared #ClassRule jenkinsRule = new JenkinsRule().with(getPluginManager()), in the abstract BaseSpecification—where abstract JenkinsRule getPluginManager() is declared—if I return MyPluginManager.INSTANCE for some specs but not others, I keep getting the following error:
class org.jenkinsci.plugins.workflow.job.WorkflowJob is missing its descriptor
java.lang.AssertionError: class org.jenkinsci.plugins.workflow.job.WorkflowJob is missing its descriptor
at jenkins.model.Jenkins.getDescriptorOrDie(Jenkins.java:1600)
at org.jenkinsci.plugins.workflow.job.WorkflowJob.getDescriptor(WorkflowJob.java:421)
at hudson.model.ItemGroupMixIn.createProjectFromXML(ItemGroupMixIn.java:285)
at jenkins.model.Jenkins.createProjectFromXML(Jenkins.java:3989)
at javaposse.jobdsl.plugin.JenkinsJobManagement.createNewItem(JenkinsJobManagement.java:517)
at javaposse.jobdsl.plugin.JenkinsJobManagement.createOrUpdateConfig(JenkinsJobManagement.java:141)
at javaposse.jobdsl.dsl.AbstractDslScriptLoader.extractGeneratedJobs_closure4(AbstractDslScriptLoader.groovy:204)
at groovy.lang.Closure.call(Closure.java:414)
at groovy.lang.Closure.call(Closure.java:430)
at javaposse.jobdsl.dsl.AbstractDslScriptLoader.extractGeneratedJobs(AbstractDslScriptLoader.groovy:197)
at javaposse.jobdsl.dsl.AbstractDslScriptLoader.extractGeneratedItems(AbstractDslScriptLoader.groovy:184)
at javaposse.jobdsl.dsl.AbstractDslScriptLoader.runScripts_closure1(AbstractDslScriptLoader.groovy:63)
at groovy.lang.Closure.call(Closure.java:414)
at groovy.lang.Closure.call(Closure.java:430)
at javaposse.jobdsl.dsl.AbstractDslScriptLoader.runScripts(AbstractDslScriptLoader.groovy:46)
at BaseJobScriptsSpec.generateDslItems(BaseJobScriptsSpec.groovy:241)
at BaseJobScriptsSpec.setupSpec(BaseJobScriptsSpec.groovy:38)
It seems like whichever PluginManager is used first changes state somewhere, either in a temporary file directory or elsewhere, that causes the error on the next test that uses a JenkinsRule with a different PluginManager. As it is now MyPluginManager is just a copy/paste of org.jvnet.hudson.test.TestPluginManager while I get this proof of concept to work.
What am I doing wrong here? Thank you.
EDIT 2021-08-04 Adding link to repo with reproduced error:
https://github.com/matthiasdenu/plugin-manager-bug/blob/main/src/test/groovy/CustomPluginMangerSpecification.groovy#L12

Spring boot test mutliple projects with same bean name

I have multiple spring projects as part of a single umbrella project. Two of them are AuthServer and BackendApplication. AuthServer, as name suggests is used only for auth purposes and rest is handled by BackendApplication. Now I am trying to write tests inside BackendApplication that also need to use auth related work. For that I have added AuthServer as a test dependency to BackendApplication. Now the problem is that, both projects have beans names Utility because of which I get DuplicateBeanException when I am including both contexts in my test. But I can disable any of them as they are necessary. Is there a way around it?
Could you name your beans, for example:
#Bean(name = "my-utility-1")
public Utility createUtility1() {
return new Utility();
}
// or
#Component(value = "my-utility-2")
public class Utility {
...
}
and refer to them by #Qualified
#Autowired #Qualified("my-utility-1")
private Utility myUtility;
Not related to your question, but i think you can mock AuthServer when testing BackendApplication.

spring boot app cannot load bundle properties files

I am building an app that mostly provide REST services, nothing fancy. since my data consumed by the app can have multiple languages I thought about using the bundle files.
I created 3 files, one with the default file name and another two with specific languages. The files created using intellij IDE I am using.
I followed this guide https://www.baeldung.com/java-resourcebundle however on each run I am getting:
MissingResourceException: Can't find bundle for base name tp_app_strings, locale en_US
I tried numerous articles but none of them seems to resolve the issue.
One fun fact is that if I am using the #Value("classpath:tp_app_strings.properties") on a 'Resource' field I am able to get a reference to that file, so it spring is able to find it.
Additional thing that I tried was to create a WEB-INF directory and place the files there (read it in some article) but still no positive affect
The project structure is quite straight forward:
Spring boot version 2.2 running tomcat.
Any suggeestions would be highly appriciated
You can load the .properties file to the application context using #PropertySource annotation instead using #Value to load the .properties file to a org.springframework.core.io.Resource instance.
The usage;
#Configuration
#PropertySource("classpath:tp_app_strings.properties")
public class DefaultProperties {
#Value("${property1.name}") // Access properties in the above file here using SpringEL.
private String prop1;
#Value("${property2.name}")
private String prop2;
}
You wouldn't need java.util.ResourceBundle access properties this way. Use different or same class to load other .properties files as well.
Update 1:
In order to have the functionality of java.util.ResourceBundle, you can't just use org.springframework.core.io.Resource class. This class or non of it sub-classes don't provide functions to access properties by its name java.util.ResourceBundle whatsoever.
However, if you want a functionality like java.util.ResourceBundle, you could implement something custom like this using org.springframework.core.io.Resource;
#Configuration
public class PropertyConfig {
#Value("classpath:tp_app_strings.properties")
private Resource defaultProperties;
#Bean("default-lang")
public java.util.Properties getDefaultProperties() throws IOException {
Properties props = new Properties();
props.load(defaultProperties.getInputStream());
return props;
}
}
Make sure to follow correct naming convention when define the property file as java.util.Properties#load(InputStream) expect that.
Now you can #Autowire and use this java.util.Properties bean wherever you want just like with java.util.ResourceBundle using java.util.Properties#getProperty(String) or its overloaded counterpart.
I think it's problem of you properties file naming convention. use underline "_" for specifying locale of file like
filename_[languageCode]_[regionCode]
[languageCode] and [regionCode] are two letters standard code that [regionCode] section is optional
about code abbrivation standard take a look on this question
in your case change file name to tp_app_strings_en_US.properties

Injecting default "management.endpoints.web.base-path" value in Spring Boot 2.1

I'm trying to inject "management.endpoints.web.base-path" into my class's field that I need to know. I did a few hours of search for it, but all the answer is "how to customize your endpoint" by setting management.endpoints.web.base-path in the application.xml(or yaml), not "how to get a default of management.endpoints.web.base-path".
Simple code as below was expecting to grab whatever variable loaded when Spring Boot app is starting up, but nothing was retrieved in the variable.
#Autowired
private Environment environment;
public void myMethod(){
final String actuatorBase = environment.getProperty("management.endpoints.web.base-path");
}
If I define it in the application.properties I should be able to load it for sure, but I'd like to know why the default("/actuator") can't be retrieved here. However when I run the application, I had no problem to access all the actuator related functionality endpoint through /actuator.
Since it doesn't work, injecting the variable with #Value annotation also doesn't work either.
When I checked the environment variable in the debugger, I was able to see application.yaml is loaded and all the overrides variables are there, too, but not all the default "management" stuff was there.
Any idea? This app has some custom configuration, not using all the AutoConfigurer stuff, so wondering if there is specific autoconfig I need to use to make it happen.
I'm using Spring Boot 2.1.0.RELEASE.
Self answering here.
WebEndpointProperties is the one that loads all the management.endpoints.web prefix properties, so simply
#Autowired
private WebEndpointProperties webEndpointProperties;
in the class and then
String actuatorWebBasePath = this.webEndpointProperties.getBasePath();
in my method gave me a base path(/actuator).

Add property to entity in spring data REST

I am trying out the ResourceProcessor interface in Spring Data REST. I don't think my Processor ever gets called. No error message either.
Here is my processor (in Groovy):
#Autowired
PersonService personService
#Override
public Resource<Person> process(Resource<Person> resource) {
resource.content.isAdult = personService.isAdult(resource.content)
// sanity check: does this link get added?? (NOPE!!)
resource.add(new Link("http://localhost:8080/people", "added-link"))
log.info "## resource.content.isAdult ==> ${resource.content}"
return resource
}
Any help would be most appreciated!! You can see the entire project here in GitHub: https://github.com/txiasummer/spring-data-rest-examples
Finally got it to work! It turns out to be something completely trivial and I can't believe I missed it. I have a PersonProcessor classes which implements Spring's native ResourceProcessor interface. But PersonProcessor is still just a basic class that must be injected by Spring!! I think I was getting it confused with #Projection, which will be recognized automatically and does not need to be injected explicitly.
I addd #ComponentScan to my Application.groovy and now everything is working swimmingly. Alternatively, you an also manually define the PersonProcessor class and its service PersonService class as #Bean in Application.groovy. Again, you can see the whole project here: https://github.com/txiasummer/spring-data-rest-examples

Resources