I set the view config of spring boot app as:
#Configuration
public class ViewConfig extends WebMvcConfigurerAdapter {
public static final String[] SCRIPTS = {
"nashorn/ejs.min.js",
"nashorn/polyfill.js",
"nashorn/render.js"
};
#Bean
public ViewResolver viewResolver() {
ScriptTemplateViewResolver viewResolver = new ScriptTemplateViewResolver();
viewResolver.setPrefix("templates/");
viewResolver.setSuffix(".ejs");
return viewResolver;
}
#Bean
public ScriptTemplateConfigurer viewConfigurer() {
ScriptTemplateConfigurer configurer = new ScriptTemplateConfigurer();
configurer.setEngineName("nashorn");
configurer.setScripts(SCRIPTS);
configurer.setRenderFunction("render");
configurer.setSharedEngine(false);
return configurer;
}
}
and my maven structure as:
App
|-- pom.xml
`-- src
|-- main
|-- java
| `-- config
| `-- ViewConfig.java
| `-- Application.java
|-- resources
| `-- nashorn
| `-- ejs.min.js
| `-- polyfill.js
| `-- render.js
| `-- templates
| `-- index.ejs
However, when I run with command mvn spring-boot:run I got to a problem failed to load script with root cause:
java.lang.IllegalStateException: Resource [nashorn/ejs.min.js] not found
My purpose is that I want to build a isomorphic app with Java and ReactJs but I got to these problems one week ago and until now I cannot solve these problem.
Related
I have a Spring Boot Web project that has a Spring Boot JPA project as a dependency like so:
spring_boot_web
|__.../application.yml
|
|__spring_boot_jpa
| |__.../data.properties
| |__.../data-test.properties
| |__.../data-dev.properties
| \__pom.xml
|
|__pom.xml
Web project uses the default application.yml file and jpa uses a properties file as yml are not supported by #PropertySource annotation.
I can run them alone flawlessly but when I try to include the jpa inside web there are problems creating the beans related to db. Is there any way to have those project running their own config files?
I just got it working. As the JPA project does not stand on its own (only for testing purposes) I just left some properties for the profiles I want that project to run standalone and then the main properties file under the web project. The structure is as follows:
spring_boot_web
|__.../application.yml
|
|__spring_boot_jpa
| |__.../application-test.yaml
| |__.../application-dev.yaml
| \__pom.xml
|
|__pom.xml
And then I made sure that there was only one #SpringBootApplication in between both projects altogether.
Also keep in mind that the main #SpringBootApplication has to be in a package in common for both projects:
spring_boot_web
|__foo.bar.core
| \__SpringWebApplication.java <- main #SpringBootApplication
|
|__foo.bar.core.web
| \__...
|
\__spring_boot_jpa
\__foo.bar.core.services
\__...
I have a published gradle plugin which looks something like this:
|__root
| |
| |
| |__java
| | |__SomeJavaClass.java
| | |__SomeJavaClass2.java
| |
| |__kotlin
| |__MyPluginClass.kts
| |__MyTaskClass.kts
| |__Utils.kts
I would like to include this plugin as a project in my multi project build instead of publishing it to a repo for easier developement.
This plugin has 3 Kotlin files Project A is using. MyPluginClass.kts has my own plugin class, MyTaskClass.kts has my own task class and Utils.kts contains only kotlin functions. The java classes are used in MyPlugin and MyTask.
It is being put on Project A's build.gradle.kts classpath as
classpath("com.my:custom.plugin:version")
A very simplified project structure I would like to achieve:
root
|
|__Project A
| |
| |__build.gradle.kts
| |__x.gradle.kts
| |__y.gradle.kts
| |__settings.gradle
|
|__Project build-logic
| |
| |__build.gradle.kts
| |
| |__java
| | |__SomeJavaClass.java
| | |__SomeJavaClass2.java
| |
| |__kotlin
| |__MyPluginClass.gradle.kts
| |__MyTaskClass.gradle.kts
| |__Utils.gradle.kts
I'm trying to create plugins from those kotlin files and include them in my main build because i need them precompiled, but i cant seem to find a way to put them on Project A's classpath when build.gradle is running there. Is it even possible? what would be the proper solution?
I'm using gradle 7.3
You can combine multiple, independent, Gradle projects using composite builds. The same is also true for Gradle plugins.
Including a Gradle plugin from another directory is documented in the Testing Gradle plugins section.
So if you have a shared-build-logic project that provides a Gradle plugin with an ID my.shared-build-logic, and you want to use that in project-a.
my-projects/
├── shared-build-logic/
│ ├── src/
│ │ └── ...
│ ├── build.gradle.kts
│ └── settings.gradle.kts
└── project-a/
├── src/
│ └── ...
├── build.gradle.kts
└── settings.gradle.kts
Then you need to include shared-build-logic in your project-a Gradle settings file.
// my-projects/project-a/settings.gradle.kts
rootProject.name = "project-a"
pluginManagement {
includeBuild("../shared-build-logic")
}
Now, so long as shared-build-logic correctly provides a Gradle plugin, in project-a you can reference that plugin.
// my-projects/project-a/settings.gradle.kts
plugins {
id("my.shared-build-logic")
}
Finnaly figured out. I didn't create plugins from build-logic, left them as kotlin files. Since it is a separate gradle project, i can just build the project and point project A's classpath to the produced jar file like
buildscript {
dependencies {
classpath(files("path.to.the.jar"))
}
}
this way i can access methods and the MyTask from Project A.
The other issue was that i wanted to apply MyPlugin like
plugins{
id("my-plugin-name")
}
which wasnt working, i guess because it is a class. But now since i had the whole project jar on my build classpath, i can do this:
apply<my-plugin-name>()
I have a spring boot project with the following structure
src
|--- main
| |--- java
| | |--- io.example.config
| | | |--- AppConfig (Annotated #Cofiguration)
| | |--- io.example.beans
| | | |--- Bean1 (Annotated #Component)
| | | |--- Bean2 (Annotated #Component)
| | |--- io.example.repository
| | | |--- Repo (DynamoDB Crud Repo; Annotated #EnableScane)
| | |--- io.example.main
| | | |--- Application (Annotated #SpringBootApplication)
| |--- module-info.java
|--- test
| |--- java
| | |--- io.example.main
| | | |--- IntTest (Annotated #SpringBootTest)
The code in the IntTest class looks like
#RunWith(SpringRunner.class)
#SpringBootTest
public class IntTest {
...
}
When I run the tests from IntelliJ it runs fine. But I run it from maven mvn test it throws the following error
Unable to find a #SpringBootConfiguration, you need to use #ContextConfiguration or #SpringBootTest(classes=...) with your test
I read some of the documentation and similar questions in SO. Most of the solution rectifies the package alignment between source and test folder. Which is not a problem in my case.
The test runs fine with mvn test when I do the following I explicitly define the context dependencies
package io.example.main;
import org.springframework.test.context.junit4.SpringRunner;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
import io.example.config.AppConfig;
import io.example.beans.Bean1;
import io.example.beans.Bean2;
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = { Application.class, AppConfig.class, Bean1.class, Bean2.class })
#SpringBootTest
public class IntTest {
...
#Autowired
private Bean1 b1;
#Autowired
private Bean2 b2;
#Test
public void testRandom() {
/* assert statements */
}
}
I can do the above, but is there any way I can run the tests without explicitly defining ContextConfiguration?
Try to put your Application (Annotated #SpringBootApplication) class in the package that is root of other packages. In your case it is io.example package.
#piradian has already provided a correct answer, I'll try to explain why is it correct.
#SpringBootTest annotation when placed on test in its most simplistic way (without parameters) tries to mimic the the process of starting the microservice for the test as precise as possible.
There are basically two steps it should do when it comes to the configuration retrieval:
Find the spring boot application
Find all configurations / components that should be loaded
For the first step, it first tries to find the #SpringBootConfiguration annotation. This is a meta-annotation placed on #SpringBootApplication annotation. This is required to find all the registered components / configurations.
So it starts with the package where the test resides (io.example.main) and if it finds class with #SpringBootConfiguration in the same package (and yes, it founds it) - then it means that this is the base package to search for all configurations / components.
If it doesn't find a class like this, then it goes one package up (io.example) and start searching again, then if not found goes for (io)
When the class is found, it start to search for configuration / components downwards starting with the package where the application resides. This is exactly how spring boot application works. And this is the source of the failure:
io.example.main package doesn't have any "sub-packages" so the spring boot test finds nothing and that's why test fails.
If you move the SpringBootApplication one package up, this solves the issue.
, because now the first step of the process described above searches in io.example.main package, finds nothing, searches in io.example, finds the required class and this is where it starts the second step from.
Now, if you use #SpringBootTest in conjunction with #ContextConfiguration this is like saying to spring boot: "Don't activate this two-phase search, just take the configuration classes that I supply and start from there". That's why it works for you with #ContextConfiguration
i am currently working on a project consisting of several modules which are all spring managed. I am now trying to autowire a service of module A into module B. This service is configured using a application.yml config file in module A. When using a standalone version of module A everything is working fine and config values are correctly injected into the fields annotated with #Value("${...}"). But if I use this service from module B, its construction fails due to spring being unable to resolve the placeholders given in the annotations.
So it seems like autowiring the service into another project renders it unable of finding the config file. Is there any way of resolving this issue?
Thanks for your help!
EDIT: This is how the relevant parts of the config class look:
#EnableKafka
#Configuration
#EnableElasticsearchRepositories(basePackages = "...")
public class ElasticsearchConfig {
#Value("${elasticsearch.home}")
private String elasticsearchHome;
#Value("${elasticsearch.cluster}")
private String clusterName;
#Bean
public Client client() {
Settings elasticSettings = Settings
.builder()
.put("path.home", elasticsearchHome)
.put("cluster.name", clusterName)
.put("client.transport.sniff", true)
.build();
PreBuiltTransportClient client =
new PreBuiltTransportClient(elasticSettings);
try {
client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9300));
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
return client;
}
...
}
These values are then used to create the beans necessary to build an elasticsearch client . The corresponding application.yml looks something like this:
elasticsearch:
cluster: elasticsearch
home: "/path/to/elasticsearch-6.4.2/"
kafka:
bootstrap-servers: localhost:9092
...
Here is the relevant part of the project structure:
Project
|-- module A
| `-- src
| |-- main
| | `-- java
| | |-- ElasticsearchConfig.java
| | |-- SomeService.java
| | `-- ServiceUsedFromA.java
| `-- resources
| `-- application.yml
`-- module B
`-- src
`-- main
|-- java
| `-- ServiceUsedFromB.java
`-- resources
`-- ...
If SomeService is autowired in ServiceUsedFromA everything is working as expected, if autowired into ServiceUsedFromB (which is also spring based) the above mentioned issue occurs.
After a substantial amount of searching and trying out different ideas to fix the issue, I have finally found a solution:
I switched from using a YAML config file to using application.properties placed in the resource folder mentioned in the project structure posted above. This allowed me to specify the property file via a #PropertySource(value = "classpath:application.properties") annotation in ElasticSearchConfig.java (which is not possible for YAML configs).
Now spring seems to be able to pick up the config file, even if the service is autowired into another module.
Thanks for your effort :)
I have a Spring Boot project where project structure looks like below
example(artifactId = example)
+- demo(artifactId = demo)
| +- src
| | +-main
| | +-java
| | +-com
| | +-example
| | +-DemoService
| | +-resources
| | +-application.properties
| +- pom.xml
+- demo2(artifactId = demo2)
| +- src
| | +-main
| | +-java
| | +-resources
| | +-application.properties
| +- pom.xml
+-pom.xml
In this project "demo2" is the dependency of "demo". The "example" module is the parent of both demo and demo2. The
The problem is that when I set the property(site.password=password) in application.properties of demo, I can't resolve it in demo module like this
#Service
public class DemoService {
#Value("${site.password}")
private String password;
}
But if I set it to the application.properties in demo2, it can be solved in the DemoService in demo module.
Thanks in advance!
To clarify:
Demo2 is the main class.
You have the same classpath resource (classpath:application.properties) on both jars, only one will be visible. Usually, configuration should not be packaged in a jar. It should be specified in the package with main method (demo2 in your case).
You can also specify some default values for #Value annotations like: #Value("${site.password:mypassword}") Details
If you still want to include properties in a jar, try putting it in a unique directory like: src/main/resources/com/example/demo.properties and include it in demo2 via spring.config.location.
Application properties packaged inside your jar takes precedence, more details can be found there https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
But you can also set which properties file to use like this
--spring.config.location=classpath:/mydefault.properties