I'm using the Tapestry5 tapx template library to send an html email, as per this example.
When I run the example I get the following error:
Caused by: java.lang.RuntimeException: No service implements the interface org.springframework.context.ApplicationContext.
at org.apache.tapestry5.ioc.internal.RegistryImpl.getService(RegistryImpl.java:560)
at org.apache.tapestry5.ioc.internal.ObjectLocatorImpl.getService(ObjectLocatorImpl.java:44)
All the tapestry-* jars, including tapestry-spring-5.1.05.jar are in my classpath.
Any clues as to what I'm missing?
Figured it out. SpringIOC loads all modules it find on the classpath. The SpringModule, in tapestry-spring.jar, attempts to initialise the ApplicactionContext service, which causes the problem.
Removing tapestry-spring.jar from the classpath fixes the problem.
Follow the directions on the web site carefully; my guess is that you are not using the special TapestrySpringFilter (instead of the normal TapestryFilter).
It's been a while since I looked at this code; I can't remember if the ApplicationContext is exposed as a service or injectable object. Seems like it should be.
Fair enough; not sure what you situation is, but you should look in more detail at what TapestrySpringFilter does in terms of set up and replicate it into your standalone app's startup. There's some special bootstrapping magic that you will want to leverage.
Related
This question asks for some specifics about more general topic regarding modularization of bean validation I asked before.
In question linked above, following this documentation and this post I split annotation and ConstraintValidator definition into 2 java modules, and linked them together using ServiceLoader as shown in documentation here. Works, mostly. But there is one unsolved issue, that it does not work for validation defined via XML, which I did according to documentation again. What does not work: The pairing between annotation and ConstraintValidator is not set, the service loader stuff is not used at all.
To recap: I have working setup using this ServiceLoader approach and it works when validating stuff coming through rest layer. All paired correctly.
BUT! We are getting these DTOs also through kafka. And here we have two different flows. There is some initialization of common ConstraintValidators on startup, and then:
if we first get REST message, ServiceLoader stuff is discovered only at this request time, some next initialization is done seemignly, and after that even kafka messages works, meaning pairing for custom validator is available everywhere. (Great!)
if kafka message arrives first though(typical), no service loader stuff is consulted and somehow it 'destroys' the configuration in way, that even if later rest request comes it won't work either, saying, that there is no ConstraintValidator for given annotation. The initialization is completed somehow defectively.
validation.xml is as easy as:
<validation-config
xmlns="http://xmlns.jcp.org/xml/ns/validation/configuration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/validation/configuration validation-configuration-2.0.xsd"
version="2.0">
<constraint-mapping>/META-INF/validation-constraints.xml</constraint-mapping>
</validation-config>
notes:
2.0 version is because of hibernate-validator 6.2.0 which comes from spring dependency management.
Why not use annotation and dump this xml stuff altogether? Not mine file, unmodifiable.
If there is some trivial newbie mistake, please advise. Maybe there is some way how to kick in service loader functionality into action in validation.xml file, I'm not aware of and cannot find anywhere.
EDITS/suggestions:
A: try to inject validator on startup to make sure it's loaded:
#Autowired
private Validator validator;
#EventListener(ApplicationReadyEvent.class)
public void logReady() {
System.out.println(validator.toString());
}
did print initialized validator, did not help though.
Project structure:
Here is the repository (no class exceeds 20 lines of code): https://github.com/MoskovchenkoD/spring5-jokes
Here is the problem: Service implementation isn't used, and 'joke' attribute doesn't get printed on the page (just '123'). Controller's #RequestMapping method is simply ignored or bypassed.
How to fix it? I was following a step-by-step video from generating a project at start.spring.io to launching it.
Much appreciated!
Yet another childish error =(
I moved the Application class one level up and now it works fine.
In a Spring Boot application how do you register custom converts to be used when processing application configuration?
I have made a custom convert (org.springframework.core.convert.converter.Converter) so it can be used by the ApplicationConversionService/Binder to parse #ConfiguraitonProperties defined in application.properties and application.yaml configuration files but do not know how to register it.
I have tried the solution here https://stackoverflow.com/a/41205653/45708 but it creates an instance of my converter after the application configuration parameters have been processed.
I ran into this issue myself recently. From what I can tell, the key issue is that binding to configuration properties occurs very early in the Spring startup process, before the Application Context is fully initialized. Therefore the usual methods for registering a converter are not reliable. In fact the ConversionService used for configuration binding appear to be a one-off and not really connected to the ConversionService that is stored in the Application Context.
I was able to get something working but it feels like a hack, as it relies on internal implementation details that may work today but not tomorrow. In any case, this is the code I used:
((ApplicationConversionService) ApplicationConversionService.getSharedInstance()).addConverter(myCustomConverter);
The trick I found was to make sure this gets called as soon as possible at application startup so that it gets called before the configuration binding where it's needed. I put it in a #PostConstruct block inside my main #SpringBootApplication class as this seemed to get invoked early on, at least in my case.
I'm developing my first Tapestry application with a login system based on a Hibernate database.
On one page with a session object, I want to call my Authenticator service class, which also gets the session injected and does some stuff. My problem is, I can't get any services to run, it's been very frustrating, despite me following simple guides like this one: http://code.google.com/p/shams/wiki/Service
In my services package, I got the Authenticator.java and AuthenticatorImpl.java interface and implemented class. In the AppModule class, I call
binder.bind(Authenticator.class, AuthenticatorImpl.class);
And in my page 'ShowAllUsers' I inject my Authenticator service object:
...
public class ShowAllUsers{
#Inject
private Session session;
#Inject
private Authenticator authenticator;
...
}
But when I load the page on my server, I receive following error:
org.apache.tapestry5.ioc.internal.OperationException
Error obtaining injected value for field de.webtech2.pages.user.ShowAllUsers.authenticator: No service implements the interface de.webtech2.services.Authenticator.
trace:
- Creating instantiator for component class de.webtech2.pages.user.ShowAllUsers
- Running component class transformations on de.webtech2.pages.user.ShowAllUsers
- Injecting field de.webtech2.pages.user.ShowAllUsers.authenticator
But my AppModule does bind the class to the interface successfully. In the Maven build console I can read "Authenticator: DEFINED" and if I try to bind it in another module, it complains because it's bound in AppMopule already.
Why doesn't tapestry see the implementation? What am I doing wrong?
Glad you checked the startup log output, that's certainly the first "sanity check" towards addressing this problem.
I think uklance has the right idea: do a clean build, make sure you don't have multiple classes named Authenticator floating around ... perhaps from a 3rd party library. I'm always having problems where I accidentally import a non-Tapestry class that happens to be named "Resource" or something.
I haven't solved the issue itself but I found a workaround that fixes it. As you might find on the internet, Tapestry allows for auto-reloading classes. Pages and components do work fine, services have some limitations -- this is where there seem to arise issues. Tomcat doesn't link the interface to the implementation.
Fix: A simple restart of eclipse solves this. Meh.
(This also fixes the "method not found" error if you added a new method to an existing service)
Also, when I execute mvn clean, everything gets screwed many times over. Eclipse can no longer resolve the simplest class and package references. Classes in the same package can no longer be found, or references to the javax.internet package lead into eternal nothingness -- whereas everything was working just fine a moment ago.
Fix:
Right-click eclipse project -> Properties -> Maven
Tick the checkbox for "Resolve dependencies from Workspace projects" and hit Apply.
If it is already checked, uncheck -> apply, then recheck -> apply. Eclipse should go sane again -- until next time...
When starting WebSphere, I get this exception:
Could not instantiate bean class [org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter]:
Constructor threw exception; nested exception is java.lang.ClassCastException:
com.ibm.xtq.xslt.jaxp.compiler.TransformerFactoryImpl incompatible with
javax.xml.transform.TransformerFactory
Caused by: java.lang.ClassCastException: com.ibm.xtq.xslt.jaxp.compiler.TransformerFactoryImpl
incompatible with javax.xml.transform.TransformerFactory
at javax.xml.transform.TransformerFactory.newInstance(Unknown Source)
at org.springframework.http.converter.xml.AbstractXmlHttpMessageConverter.<init>(AbstractXmlHttpMessageConverter.java:47)
at org.springframework.http.converter.xml.SourceHttpMessageConverter.<init>(SourceHttpMessageConverter.java:45)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.<init>(AnnotationMethodHandlerAdapter.java:197)
This doesn't seem have any impact on any beans in my applicationContext.xml but it's still odd. For me, this looks as if IBM classes are leaking into my application.
How can I fix this? I already set the option "Access to internal server classes" to "Restrict".
It was indeed a class-loading issue, however this cannot be solved by changing class-loader settings.
The problem was that the xml-apis and javax.xml jars were being imported over some maven dependencies.
Since we already set the class loader policies for the application to PARENT_LAST, the javax.xml.transform.TransformerFactory was being loaded from the WebApp-Class loader from our jar files.
However its implementation 'com.ibm.xtq.xslt.jaxp.compiler.TransformerFactoryImpl' was coming from the server class loader, this one was linked to the javax.xml.transform.TransformerFactory provided by the JDK/JRE.
Since the classes were loaded from different sources a ClassCastException was thrown.
Removing all dependencies to xml-apis / xerces / javax.xml jars solved the problem.
Since these APIs are now part of the JDK they no longer need to be imported.
... and if you wonder why I know so much about this issue: I work together with Aaron. ;)
I can't speak for Restrict as I have no personal experience with it,But I think the problem is more to do with IBM Class Loader. The class you are referring to is part of IBM Java implementation of TransformerFactory, I think you can try one of the following to solve this issue on hand
Either change the server class loader policy to PARENT_LAST (This way class loader will find the class from application's local class path, before going to up the chain all the way to java run time)
The other option would be look at the jaxp.properties file, I think it is located in (was_root\java\jre\lib), I only read about this option never actually used it
Why do you say IBM classes are leaking into your application?
The TransformerFactory is asked to create a newInstance. It follows a sequence of steps to determine which TransformerFactory to use. If none of the config is specified, it simply chooses to use the default factory.
Here is the javadoc for TransformerFactory:
http://download.oracle.com/javase/1.5.0/docs/api/javax/xml/transform/TransformerFactory.html#newInstance()
What is the OS ? Is that AIX?
http://www.ibm.com/developerworks/java/jdk/aix/j664/sdkguide.aix64.html
Looking at this doc (link above) for AIX it tells me that this is the default Impl:
javax.xml.transform.TransformerFactory
Selects the XSLT processor. Possible values are:
com.ibm.xtq.xslt.jaxp.compiler.TransformerFactoryImpl
Use the XL TXE-J compiler. This value is the default.
Post back additional information so that we can try and troubleshoot this.
HTH
Manglu