When I start Spring Boot application with Spring-Devtools enabled and classes generated from the WSDL schema I get:
Caused by: java.lang.IllegalArgumentException: org.wsdl.WsdlServiceWs referenced from a method is not visible from class loader
I have a project based on Spring Boot with some of the classes generated from the WSDL file using the org.apache.cxf:cxf-codegen-plugin plugin. Generated classes are stored in target/generated/wsdl/** directory. The name of the package of generated classes differs from the project package name.
I tried several exclusions following the documentation:
https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#using-boot-devtools-restart-exclude
But all my attempts failed.
restart.exclude.wsdl=target/generated/wsdl
restart.exclude.wsdl=org.wsdl.*
restart.exclude.wsdl=**WsdlServiceWs.class
I want to have Spring-Devtools enabled, having org.wsdl.** generated classes excluded from the restart cycle.
The problem was, that I tried to use the WsdlServiceWs which was in fact an interface returned by WsdlServiceWsService. I had the WsdlServiceWs interface returned as a bean in the configuration:
...
#Bean
public WsdlServiceWs wsdlService() {
return new WsdlServiceWsService().getService();
}
...
I have not thought that this will be the problem. Simply changing the bean to the following:
...
#Bean
public WsdlServiceWsService wsdlService() {
return new WsdlServiceWsService();
}
...
Did the work.
Edit:
This solution only moved the invocation of exception from the Bean creation phase to the execution phase. The issue is still not resolved.
You Can't
because the devtools only check the class parent path, not every folder, you can add an breakpoint on ChangeableUrls.java:59
private ChangeableUrls(URL... urls) {
DevToolsSettings settings = DevToolsSettings.get();
List<URL> reloadableUrls = new ArrayList<>(urls.length);
for (URL url : urls) {
if ((settings.isRestartInclude(url) || isDirectoryUrl(url.toString())) && !settings.isRestartExclude(url)) {
reloadableUrls.add(url);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Matching URLs for reloading : " + reloadableUrls);
}
this.urls = Collections.unmodifiableList(reloadableUrls);
}
you can see the url is file:/xxx/target/classes/
so, you can't exclude one class by this way
Related
I'm adding module-info.javas to Ikonli packages and I'm running into trouble with their service classes. ikonli-core defines an interface called IkonHandler. ikonli-fontawesome5-pack has a service provider for the IkonHandler called FontAwesomeSolidIkonHandler. These service prodivers are used by ikonli-javafx's IkonResolver.
Given this, I created these module definitions:
module org.kordamp.ikonli.core {
exports org.kordamp.ikonli;
}
module org.kordamp.ikonli.javafx {
exports org.kordamp.ikonli.javafx;
uses org.kordamp.ikonli.IkonHandler;
requires javafx.graphics;
requires org.kordamp.ikonli.core;
}
module org.kordamp.ikonli.fontawesome5 {
exports org.kordamp.ikonli.fontawesome5;
provides org.kordamp.ikonli.IkonHandler with org.kordamp.ikonli.fontawesome5.FontAwesomeBrandsIkonHandler, org.kordamp.ikonli.fontawesome5.FontAwesomeRegularIkonHandler, org.kordamp.ikonli.fontawesome5.FontAwesomeSolidIkonHandler;
requires org.kordamp.ikonli.core;
requires org.kordamp.jipsy;
}
They might not be complete, but they are complete enough so that when my application starts, it fails with this error:
java.lang.UnsupportedOperationException: Cannot resolve 'fas-user'
which is throw when no handler managed to load the icon:
public IkonHandler resolveIkonHandler(String value) {
requireNonNull(value, "Ikon description must not be null");
for (IkonHandler handler : HANDLERS) {
if (handler.supports(value)) {
return handler;
}
}
throw new UnsupportedOperationException("Cannot resolve '" + value + "'");
}
The reason why that is happening is that HANDLERS is empty. HANDLERS is loaded at startup by this code:
ClassLoader classLoader = IkonResolver.class.getClassLoader();
ServiceLoader<IkonHandler> loader = ServiceLoader.load(IkonHandler.class, classLoader);
for (IkonHandler handler : loader) {
HANDLERS.add(handler);
handler.setFont(Font.loadFont(classLoader.getResource(handler.getFontResourcePath()).toExternalForm(), 16));
}
but with the module definitions quoted above, ServiceLoader.load(IkonHandler.class, classLoader) finds no service providers.
What am I missing?
What I was missing was requiring fontawesome5 in the module-info.java of my application:
requires org.kordamp.ikonli.fontawesome5;
"My app was not requiring the the fontawesome5 module." Your app doesn't need to require it. In fact, your app shouldn't require it. You're missing the point of uses/provides.
Edit You make a provider available by putting it on the modulepath and watching the module system go to work. Your ikonli.javafx module uses the IkonHandler interface, and your ikonli.fontawesome5 module provides an implementation of the IkonHandler interface. That's all the module system needs to bind them together. It's wrong for ikonli.javafx to require ikonli.fontawesome5. ikonli.fontawesome5 shouldn't even export the package that it's exporting, because that allows anyone who requires ikonli.fontawesome5 to access the provider classes like FontAwesomeBrandsIkonHandler directly.
Essentially I have a client .jar that requires dynamic behaviour. It will need to load resources from the classpath of it's parent application. The main application is a Spring Boot application and the client .jar is a maven dependency of that project.
I find that when storing test.xml in a subfolder of src/main/resources of the Spring Boot parent project then using this code in the dependency:
InputStream fis = SSLSocketFactoryGenerator.class.getResourceAsStream("/subFolder/etc/test.xml");
will cause a null pointer as it can't find the file. Anyone know why this is and how to resolve this?
There can be 2 possible cases why you got the NPE:
1 (most likely). You incorrectly assembled your jar and it may well happen that /subFolder/etc/test.xml simply not in classpath. Take a look at ClassLoader::getResource(String name)
public URL getResource(String name) {
URL url;
if (parent != null) {
url = parent.getResource(name);
} else {
url = getBootstrapResource(name);
}
if (url == null) { //not found in ClassPath, falling back to findResource.
url = findResource(name);
}
return url;
}
But the "default" implementation of findResource is this:
protected URL findResource(String name) {
return null;
}
So I would advice you to check your assembled jar-file.
2 (very unlikely). The class SSLSocketFactoryGenerator was loaded by a ClassLoader with the overriden methods for finding resources listed above. Actually I cannot imagine the case where we would override the behavoir of loading resources that are in classpath so we cannot load them. So 1. is most likely your case
I have a java project containing a spring boot application called processor. This project depends on a project called rules and a project called service. Every project has the same package pattern - my.com.package.
The processor and rules projects both contain classes annotated with a custom annotation #Condition. The annotation interface is annotated with #Retention(RetentionPolicy.RUNTIME). When I scan for classes annotated with #Condition from service or processor like this
private ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(
false);
scanner.addIncludeFilter(new AnnotationTypeFilter(Condition.class));
for (BeanDefinition bd : scanner.findCandidateComponents("my.com")) {
try {
Class<?> c = Class.forName(bd.getBeanClassName());
Condition condition = c.getAnnotation(Condition.class);
register(condition);
} catch (ClassNotFoundException | IOException e) {
logger.error(e.getLocalizedMessage());
}
}
The classes annotated with #Condition in the processor project have the correct class name(my.com.package.x.Class), but the classes annotated with #Condition in the rules project have an incorrect fully qualified class name(my.com.Class) and it only finds 2 out of 5 class names in the project that have the annotation.
If I change the argument to scanner.findCandidateComponents to the full package path in the rules project (my.com.package.rules) while scanning in either processor or service the scanner finds no candidates. If I use my.com.* as the argument it only finds the candidates in the processor project.
I saw a similar question here Using ClassPathScanningCandidateComponentProvider with multiple jar files? and the solution was to pass the class loader to the component provider. I tried getting the class loader of the class doing the scanning and passing it to the provider like this
scanner.setResourceLoader(new PathMatchingResourcePatternResolver(classLoader));
and it didn't change any results for me.
Silly mistake, the problem was I had the wrong version of the rules project defined in the pom for my processor project so it was using an older version of the code.
However this
Condition condition = c.getAnnotation(Condition.class);
returned null for the classes taken from the jar, so this concerns me a little if this code isn't being run from source in my workspace.
Trying to load spring beans from custom groovy file in Grails 2.3.7. I know this question has been asked before, but after hours of searching, I'm unable to find a consistent approach that loads from the classpath.
The Goal
Modularize resources.groovy into multiple custom resource files
Put custom resource files in standard location: grails-app/conf/spring
Use plugin to do the magic; minimize overhead
Tried...
//## grails-app/conf/spring/MyBeansConfig.groovy
beans {
testsvc(TestService){
msg = 'hello'
}
}
Note above, I'm using beans {}, not beans = {}, apparently it makes a difference:
resources.groovy
This works...
beans = {
loadBeans 'file:C:\\Proj\Test1\grails-app\\conf\\spring\\MyBeansConfig.groovy'
}
...and according to docs, this should too, but doesn't:
importBeans("classpath:*MyBeansConfig.groovy")
UPDATE - WORKING OPTIONS
(working for Grails 2.3.7)
Option 1: (src/java)
Following lukelazarovic advice, this approach works since Grails automatically copies (not compiles) groovy files in src/java to the classpath; works fine in eclipse and with war deployment:
//bean config files here
src/java/MyBeansConfig.groovy
src/java/FooBeansConfig.groovy
//resources.groovy
loadBeans('classpath*:*BeansConfig.groovy')
Options 2: (grails-app/conf/spring)
This approach allows for custom bean config files in grails-app/conf/spring (credits to ideascultor and mark.esher)
//bean config files here
grails-app/conf/spring/MyBeansConfig.groovy
//## resources.groovy
//for eclipse/local testing
loadBeans('file:./grails-app/conf/spring/*BeansConfig.groovy')
//for WAR/classpath
loadBeans('classpath*:*BeansConfig.groovy')
//## BuildConfig.groovy
grails.war.resources = { stagingDir, args ->
copy(todir: "${stagingDir}/WEB-INF/classes/spring") {
fileset(dir:"grails-app/conf/spring") {
include(name: "*BeansConfig.groovy")
exclude(name: "resources.groovy")
exclude(name: "resources.xml")
}
}
}
Options 3: (Custom Plugin)
If you're using custom plugins, this approach is ideal; boiler plate config gets refactored into the plugin:
Plugin Config
//## scripts/_Events.groovy
eventCreateWarStart = { warName, stagingDir ->
def libDir = new File("${stagingDir}/WEB-INF/classes/spring")
ant.copy(todir: libDir) {
fileset(dir:"grails-app/conf/spring") {
include(name: "*BeansConfig.groovy")
exclude(name: "resources.groovy")
exclude(name: "resources.xml")
}
}
}
//## MyGrailsPlugin.groovy
def doWithSpring = {
loadBeans('file:./grails-app/conf/spring/*BeansConfig.groovy')
loadBeans('classpath*:*BeansConfig.groovy')
}
Grails App
No config!...just create your bean config files using the *BeansConfig.groovy convention, good to go!
//bean config files here
grails-app/conf/spring/MyBeansConfig.groovy
Update 9/24/2015
Found some issues with option 3:
loading of duplicate resource files
spring resources not configured correctly for test-app
We managed to fix the above issue such that any resource files in grails-app/conf/spring work the same when executing Grails in eclipse, WAR, test-app, etc.
First step: we created a class to have more control over locating and loading resource files; this was necessary as some files were being loaded more than once due to cross-referenced beans.
We're using a plugin to encapsulate this functionality, so this class lives in that plugin:
class CustomResourceLoader {
static loadSpringBeans(BeanBuilder bb){
def files = ['*'] //load all resource files
//match resources using multiple methods
def matchedResourceList = []
files.each {
matchedResourceList +=
getPatternResolvedResources("file:./grails-app/conf/spring/" + it + ".groovy").toList()
matchedResourceList +=
getPathMatchedResources("classpath*:spring/" + it + ".groovy").toList()
}
//eliminate duplicates resource loaded from recursive reference
def resourceMap = [:]
matchedResourceList.each{
if(it) resourceMap.put(it.getFilename(), it)
}
//make resources.groovy first in list
def resourcesFile = resourceMap.remove("resources.groovy")
if(!resourcesFile)
throw new RuntimeException("resources.groovy was not found where expected!")
def resourcesToLoad = [resourcesFile]
resourceMap.each{k,v -> resourcesToLoad << v }
log.debug("Spring resource files about to load: ")
resourcesToLoad.each{ bb.loadBeans(it) }
}
static def getPatternResolvedResources(path){
ResourcePatternResolver resourcePatternResolver =
new PathMatchingResourcePatternResolver();
return resourcePatternResolver.getResources(path);
}
static def getPathMatchedResources(path){
return new PathMatchingResourcePatternResolver().getResources(path)
}
}
Removed BeansConfig.groovy suffix; WAR generation now picks up any resources in grails-app/conf/spring
plugin, _Events.groovy
eventCreateWarStart = { warName, stagingDir ->
def libDir = new File("${stagingDir}/WEB-INF/classes/spring")
ant.copy(todir: libDir) {
fileset(dir:"grails-app/conf/spring") {
include(name: "*.groovy")
exclude(name: "resources.xml")
}
}
}
}
In the plugin definition file, call the loader from doWithSpring(), passing BeanBuilder (the delegate) as the argument (very important):
def doWithSpring = {
CustomResourceLoader.loadSpringBeans(delegate)
}
That's it, there is no requirement on users of the plugin aside from creating custom resource files in grails-app/conf/spring
I had a similar problem just a few days ago, with a groovy configuration file that I added into grails-app/conf. While this works with other resources (they are copied and available on the classpath), the problem with the groovy file was simply that it was compiled and the class file was included, i.e. not the groovy file itself.
I didn't find any good documentation on how this should be done and finally just added it to web-app/WEB-INF/classes. Groovy files placed here will be copied (not compiled) and available on the classpath.
I had the same problem with custom XML files in Grails 2.1.2.
Having XML resources in grails-app/conf/spring didn't work in production environment AFAIR.
To make it working both in development and production environments I finally put the resources into src/java. I think you can achieve the same result by putting your groovy files into src/groovy.
We can import beans from different groovy/xml file in the following way too : -
use the following in resources.groovy -
importBeans 'file:camel-beans.groovy'
OR
importBeans('classpath:/camel-config.xml')
Place camel-beans.groovy along with resources.groovy and provide package as "package spring" for first case, otherwise put it in web app classpath and use the second way to do it.
If your resources.groovy is at following path
grails-app/conf/spring/resources.groovy
and your camel-beans.groovy is at following path
grails-app/conf/spring/camel-beans.groovy
then you can reference camel-beans.groovy in resources.groovy file by adding following line in resources.groovy
importBeans('file:**/camel-beans.groovy')
I am trying to get gwt-test-utils to work. I set up the project in the following way:
src/main/java : all the java source code
src/test/java : the test source code
src/test/resources : resource files for the tests
I am building my project with gradle and eclipse. Gradle uses these directories correctly by default and I added all three of them as source directories to Eclipse.
I have successfully built and run the project and was able to execute some plain old JUnit tests as well as a GWTTestCase, so I think I set up the project and its dependencies correctly.
Now I wanted to use gwt-test-utils for some more advanced integration tests. To do so I did the following:
Add the gwt-test-utils and gwt-test-utils-csv to my dependencies
gwtTestUtilsVersion = '0.45'
testCompile group:'com.googlecode.gwt-test-utils', name:'gwt-test-utils', version:gwtTestUtilsVersion
testCompile group:'com.googlecode.gwt-test-utils', name:'gwt-test-utils-csv', version:gwtTestUtilsVersion
Add a gwt-test-utils.properties file to the directory src/test/resources/META-INF with the following content:
path/to/my/module = gwt-module
Added a class that extends GwtCsvTest to a package in the src/test/java directory. It is modeled after the second example in HowToWriteCsvScenario from the gwt-test-utils project wiki, replacing occurrence of their example classes with mine. It looks like this
#CsvDirectory(value = "gwtTests")
public class LoginLogoutTest extends GwtCsvTest
{
#Mock
private MainServiceAsync mainService;
private AppController appController = new AppController();
#CsvMethod
public void initApp()
{
appController.onModuleLoad();
}
#Before
public void setup()
{
GwtFinder.registerNodeFinder("myApp", new NodeObjectFinder()
{
#Override
public Object find(Node node)
{
return csvRunner.getNodeValue(appController, node);
}
});
GwtFinder.registerNodeFinder("loginView", new NodeObjectFinder()
{
#Override
public Object find(Node node)
{
return csvRunner.getNodeValue(appController.getRootPresenter().getCurrentlyActiveSubPresenters().iterator().next().getView(), node);
}
});
addGwtCreateHandler(createRemoteServiceCreateHandler());
}
}
added a csv-file for configuring the test to src/test/resources/gwtTests with the following content
start
initApp
assertExist;/loginView/emailTextBox
I tried executing it via the Eclipse's Run As > JUnit Test and indirectly via gradle build (which executes all the test cases, not just this one). Both lead to the same error:
ERROR GwtTreeLogger Unable to find type 'myPackage.client.AppController'
ERROR GwtTreeLogger Hint: Check that the type name 'myPackage.client.AppController' is really what you meant
ERROR GwtTreeLogger Hint: Check that your classpath includes all required source roots
The AppController class is the entry-point configured in the module I configured in gwt-test-utils.properties, which makes me think that configuration works correctly and the rest of the setup (dependencies and all) work as well.
In an earlier version I used the same file as a subclass of GWTTestCase and created an AppController instance in the same way. That worked, so I'm pretty sure the class path is setup correctly to include it as well. I also tried changing it back to the previous version just now and it still works.
I have no clue why the class is not found. Is there anything gwt-test-utils does differently which means I need to specifically set the class path for it? Otherwise it should just work, since both gradle and eclipse know about all the relevant source folders and dependencies.