Resource ServletContext resource does not exist - spring-boot

I'm working on a project (spring boot) and I have to convert xml file to Java classes using the maven jaxb2 plugin. I'm following this link:
the classes are generated the problem is when I try to unmarshall the xml I had this error:
Resource ServletContext resource [/xsd/MX_seev_031_001_05. xsd] does not exist
this is my application.properties:
context.path =xml.swift.spring.com
schema.location= xsd/MX_seev_031_001_05.xsd
this my bean of config:
#Bean
public Jaxb2Marshaller createJaxb2Marshaller(#Value("${context.path}") final String contextPath,
#Value("${schema.location}") final Resource schemaResource){
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath(contextPath);
marshaller.setSchema(schemaResource);
Map<String, Object> properties = new HashMap<>();
properties.put(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setMarshallerProperties(properties);
return marshaller;
the xsd file is under src/main/resources/xsd and this is my pom.xml:
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.12.1</version>
<executions>
<execution>
<id>add-source-for-demoapp</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<schemaDirectory>${project.basedir}/src/main/resources/xsd</schemaDirectory>
<schemaIncludes>
<include>*.xsd</include>
</schemaIncludes>
<!-- Other configuration options-->
</configuration>
</execution>
</executions>
what i'am missing?
thanks.

I had basically the same issue, when I started to use spring-boot-starter-data-rest in addition to spring-oxm (I also have spring-boot-starter-data-jpa) in my pom.xml.
The problem is with your 2nd auto injected argument;
#Value("${schema.location}") final Resource schemaResource
So instead of
#Bean
public Jaxb2Marshaller createJaxb2Marshaller(#Value("${context.path}") final String contextPath, #Value("${schema.location}") final Resource schemaResource){
//...
marshaller.setSchema(schemaResource);
//...
}
Do below;
#Bean
public Jaxb2Marshaller createJaxb2Marshaller(#Value("${context.path}") final String contextPath, #Value("${schema.location}") final String schemaLocation){
//...
Resource schemaResource = new ClassPathResource(schemaLocation);
marshaller.setSchema(schemaResource);
//...
}
Give it a try, it will work.

Related

Apache Camel SOAP/CXF request to Server (Spring Boot)

I am trying to make requests to dedicated WSDL server with the help of Apache Camel CXF.
I have the WSDL URL:
http://www.learnwebservices.com/services/tempconverter?wsdl
I've made the Java classes of WSDL using the cxf-codegen-plugin:
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>3.4.2</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<goals>
<goal>wsdl2java</goal>
</goals>
<configuration>
<wsdlOptions>
<wsdlOption>
<wsdl>${basedir}/src/main/resources/wsdl/tempconverter.wsdl</wsdl>
<packagenames>
<packagename>office.planet.integrations.merlion</packagename>
</packagenames>
</wsdlOption>
</wsdlOptions>
</configuration>
</execution>
</executions>
</plugin>
I have the following Camel route:
#Component
public class MerlionRoute
extends RouteBuilder {
#Override
public void configure() throws Exception {
from("direct:celsius-to-fahrenheit")
.process(exchange -> {
System.out.println("HELLO!!!!!");
CelsiusToFahrenheitRequest c = new CelsiusToFahrenheitRequest();
c.setTemperatureInCelsius(Double.valueOf(exchange.getIn().getHeader("num").toString()));
exchange.getIn().setBody(c);
})
.setHeader(CxfConstants.OPERATION_NAME, constant("CelsiusToFahrenheit"))
.setHeader(CxfConstants.OPERATION_NAMESPACE, constant("{{endpoint.namespace}}"))
.to("cxf:bean:cxfConvertTemp")
.process(exchange -> {
System.out.println("WE ARE HERE");
MessageContentsList response = (MessageContentsList) exchange.getIn().getBody();
CelsiusToFahrenheitResponse r = (CelsiusToFahrenheitResponse) response.get(0);
exchange.getIn().setBody("Temp in Farenheit: "+r.getTemperatureInFahrenheit());
System.out.println(r.getTemperatureInFahrenheit());
})
.end();
}
}
The Bean class of the EndPoint:
#Configuration
public class CxfBeans {
#Value("${endpoint.wsdl}")
private String SOAP_URL;
#Bean(name = "cxfConvertTemp")
public CxfEndpoint buildCxfEndpoint() {
CxfEndpoint cxf = new CxfEndpoint();
cxf.setAddress(SOAP_URL);
cxf.setServiceClass(TempConverterEndpoint.class);
cxf.setWsdlURL(SOAP_URL);
return cxf;
}
}
And the WSDL endpoint:
endpoint.wsdl=http://www.learnwebservices.com/services/tempconverter?wsdl
endpoint.namespace=http://learnwebservices.com/services/tempconverter
When I am launching the project, my route starts, but nothing happens.
Only this I can see:
2022-03-31 18:41:44.933 INFO 44313 --- [ restartedMain] o.a.c.w.s.f.ReflectionServiceFactoryBean : Creating Service {http://learnwebservices.com/services/tempconverter}TempConverterEndpointService from WSDL: http://www.learnwebservices.com/services/tempconverter?wsdl
How shall I request the data from WSDL server within the Camel CXF? What am I doing wrong?
Your route needs to be triggered. As it stands, nothing calls your from endpoint "direct:celsius-to-fahrenheit", and thus indeed, nothing happens.
Assuming you want this route to be triggered only once, you could define your from endpoint as "timer://celsius-to-fahrenheit?repeatCount=1".
See Camel Timer component.

Unable to run generated jar from spring-boot jersey

Im unable to run the generated jar file with my spring-boot with jersey project.
exception that i encounter is:
Error starting Tomcat context. Exception: org.springframework.beans.factory.UnsatisfiedDependencyException. Message: Error creating bean with name 'org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration': Unsatisfied dependency expressed through constructor parameter 1
Project runs properly when it's done via IDE (running the Main class) or when using spring-boot:run
Here are the details of the current setup:
Packaging:
jar
dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
<version>1.5.1.RELEASE</version>
</dependency>
my jersey configuration (ResourceConfig) is set to scan packages
#Component
public class JerseyConfiguration extends ResourceConfig {
public JerseyConfiguration() {
packages(true, "com.my.base.jaxrs.packages");
}
}
spring-boot-maven-plugin configured as:
org.springframework.boot
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
I also did not use the spring-boot-starter-parent but added the spring-boot-dependencies as indicated in the docs.
This is more of a workaround than an actual valid solution to use
packages(true, "my.package");
in reference to Anton's answer, i settled with this solution with the limitation that it requires resources with class level #Path or #Provider annotation:
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
provider.addIncludeFilter(new AnnotationTypeFilter(Path.class));
provider.addIncludeFilter(new AnnotationTypeFilter(Provider.class));
provider.findCandidateComponents("my.package.here").forEach(beanDefinition -> {
try {
LOGGER.info("registering {} to jersey config", beanDefinition.getBeanClassName());
register(Class.forName(beanDefinition.getBeanClassName()));
} catch (ClassNotFoundException e) {
LOGGER.warn("Failed to register: {}", beanDefinition.getBeanClassName());
}
});
I had this problem, I did not want to complicate things too much so I just registered all my jersey controllers individually.
#Configuration
public class JerseyConfig extends ResourceConfig {
JerseyConfig() {
// my old version that does not play well with spring boot fat jar
/*
packages(
"com.mycompany.api.resources"
);
*/
register(com.mycompany.api.resources.FooController.class);
register(com.mycompany.api.resources.BarController.class);
}
NOTE: I would not recommend this for large projects with many files, it will very quickly become long and unreadable and tedious to maintain.
That said, it is a working solution and you will be able to run your jar with the usual java -jar my-project.jar command.
Alternatively you could do,
#Configuration
public class JerseyConfig extends ResourceConfig {
JerseyConfig() {
BeanConfig beanConfig = new BeanConfig();
beanConfig.setResourcePackage("com.mycompany.api.resources");
}
}

SpringBoot Couchbase Integration

I want to make a filterable list of my UserTask entity with the QueryDslPredicateExecutor interface, so the parameters given in the query string will be autoprocessed into a Predicate.
I have the following classes/interfaces
public interface UserTaskQuerydslRepository extends CrudRepository<UserTask, String>,
QueryDslPredicateExecutor<UserTask>, QuerydslBinderCustomizer<QUserTask> {
#Override
default void customize(QuerydslBindings bindings, QUserTask userTask) {
...
}
}
UserTask is my class that represents the (couchbase) model
#QueryEntity
#Document(expiry = 0)
public class UserTask {
#Id
private String id;
...
}
If i annotate this class with #QueryEntity then Maven generates the QUserTask class for me
#Generated("com.mysema.query.codegen.EntitySerializer")
public class QUserTask extends EntityPathBase<UserTask> {
private static final long serialVersionUID = 493434469L;
public static final QUserTask userTask = new QUserTask("userTask");
public final StringPath id = createString("id");
...
public QUserTask(String variable) {
super(UserTask.class, forVariable(variable));
}
public QUserTask(Path<? extends UserTask> path) {
super(path.getType(), path.getMetadata());
}
public QUserTask(PathMetadata<?> metadata) {
super(UserTask.class, metadata);
}
}
To generate QUserTask i added the following lines to pom.xml
<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>1.1.3</version>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources/apt</outputDirectory>
<processor>com.mysema.query.apt.jpa.JPAAnnotationProcessor</processor>
<processor>com.mysema.query.apt.QuerydslAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>3.4.3</version>
</dependency>
</dependencies>
</plugin>
In the project we have both JPA entities and couchbase entities, that's why i have the JPAAnnotationProcessor there.
If i run the application like this i get the following error:
org.springframework.data.mapping.PropertyReferenceException: No
property findAll found for type UserTask!
I tried to annotate my UserTaskQuerydslRepository with #NoRepositoryBean, it solved my findAll problem, but when i tries to #Inject this repository to a Resource (or controller, JHipster calls it Resource) i get the following error
No qualifying bean of type [.UserTaskQuerydslRepository]
found for dependency: expected at least 1 bean which qualifies as
autowire candidate for this dependency. Dependency annotations:
{#javax.inject.Inject()}
Can anyone help me what did I do wrong?
As #mp911de said in his comment, Spring Data Couchbase doesn't have support for QueryDsl, which explains why the bean cannot be created.
I can see where your confusion comes from when reading the doc. Chapter 5 is the content common to all Spring Data store implementations. All store documentations have one chapter with that same content, which generically talk about the repository basics. So it can mention things that are not in a particular implementation.
The first sentence of the section you linked even hints at it:
Several Spring Data modules offer integration with Querydsl via QueryDslPredicateExecutor.
Several, but not the Spring Data Couchbase module unfortunately.
2016. 07. 11. : After some research, and according to answers by #mp911de, and #simon-baslé we know that Spring Data Couchbase doesn't have support for QueryDsl yet.
I found a workaround for the problem that i wanted to solve (dynamic querying, aka. filters on a list and make it pageable)
https://github.com/TeamWanari/couchbase-query-executor

How to precompile jsp in a spring boot application?

I'm using Spring boot and we were using Spring with Tomcat before that.
When we used Spring and Tomcat two years ago, we used a maven plugin to precompile the jsp.
It was really useful to avoid this compilation to be made for every first visits after a deployement.
However all maven plugin that we know dumps a web.xml file that list all jsp and associated generated servlets.
With Spring boot, it don't use web.xml anymore, so this file is ignored.
We still have the compilation and that's a security belt but there is a penalty for every first visit on each page.
Does anybody know if it's possible to precompile jsp in a Spring boot application ?
I got precompiling to work either at server start time (don't have to use JspC, so simpler build file) and at build time (much quicker server start time). I register the resulting servlets dynamically, so you don't have to manually change any files if you add/remove JSPs.
At server start time
Use ServletRegistration.Dynamic to register a JSP_SERVLET_CLASS Servlet for each JSP.
Use the initParameter jspFile to set the JSP filename (ref)
e.g. for SpringBoot in a ServletContextInitializer (ref):
#Bean
public ServletContextInitializer preCompileJspsAtStartup() {
return servletContext -> {
getDeepResourcePaths(servletContext, "/WEB-INF/jsp/").forEach(jspPath -> {
log.info("Registering JSP: {}", jspPath);
ServletRegistration.Dynamic reg = servletContext.addServlet(jspPath, Constants.JSP_SERVLET_CLASS);
reg.setInitParameter("jspFile", jspPath);
reg.setLoadOnStartup(99);
reg.addMapping(jspPath);
});
};
}
private static Stream<String> getDeepResourcePaths(ServletContext servletContext, String path) {
return (path.endsWith("/")) ? servletContext.getResourcePaths(path).stream().flatMap(p -> getDeepResourcePaths(servletContext, p))
: Stream.of(path);
}
At build time
Generate Java source files for each JSP and a web.xml with their servlet mappings using JspC (ref).
Then register these with the ServletContext (by parsing the web.xml with Tomcat's WebXmlParser, e.g. for SpringBoot:
#Value("classpath:precompiled-jsp-web.xml")
private Resource precompiledJspWebXml;
#Bean
public ServletContextInitializer registerPreCompiledJsps() {
return servletContext -> {
// Use Tomcat's web.xml parser (assume complete XML file and validate).
WebXmlParser parser = new WebXmlParser(false, true, true);
try (InputStream is = precompiledJspWebXml.getInputStream()) {
WebXml webXml = new WebXml();
boolean success = parser.parseWebXml(new InputSource(is), webXml, false);
if (!success) {
throw new RuntimeException("Error parsing Web XML " + precompiledJspWebXml);
}
for (ServletDef def : webXml.getServlets().values()) {
log.info("Registering precompiled JSP: {} = {} -> {}", def.getServletName(), def.getServletClass());
ServletRegistration.Dynamic reg = servletContext.addServlet(def.getServletName(), def.getServletClass());
reg.setLoadOnStartup(99);
}
for (Map.Entry<String, String> mapping : webXml.getServletMappings().entrySet()) {
log.info("Mapping servlet: {} -> {}", mapping.getValue(), mapping.getKey());
servletContext.getServletRegistration(mapping.getValue()).addMapping(mapping.getKey());
}
} catch (IOException e) {
throw new RuntimeException("Error registering precompiled JSPs", e);
}
};
}
Example Maven config to generate and compile the JSP classes, and generate the precompiled-jsp-web.xml:
<!-- Needed to get the jasper Ant task to work (putting it in the plugin's dependencies didn't work) -->
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina-ant</artifactId>
<version>8.0.32</version>
<scope>provided</scope>
</dependency>
<!-- ... -->
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<id>precompile-jsp-generate-java</id>
<!-- Can't be generate-sources because we need the compiled Henry taglib classes already! -->
<phase>compile</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<echo message="Precompiling JSPs"/>
<property name="compile_classpath" refid="maven.compile.classpath"/>
<property name="target_dir" value="${project.basedir}/generated-sources/jspc" />
<path id="jspc_classpath">
<path path="${compile_classpath}"/>
</path>
<typedef resource="org/apache/catalina/ant/catalina.tasks" classpathref="jspc_classpath"/>
<mkdir dir="${target_dir}/java"/>
<mkdir dir="${target_dir}/resources"/>
<jasper
validateXml="false"
uriroot="${project.basedir}/src/main/webapp"
compilertargetvm="1.8"
compilersourcevm="1.8"
failonerror="true"
javaencoding="UTF-8"
webXml="${target_dir}/resources/precompiled-jsp-web.xml"
outputDir="${target_dir}/java/" >
</jasper>
<!-- Can't use Maven to compile the JSP classes because it has already compiled the app's classes
(needed to do that becuase JspC needs compiled app classes) -->
<javac srcdir="${target_dir}/java" destdir="${project.build.outputDirectory}" classpathref="jspc_classpath" fork="true"/>
<!-- Have to copy the web.xml because process-resources phase has already finished (before compile) -->
<copy todir="${project.build.outputDirectory}">
<fileset dir="${target_dir}/resources"/>
</copy>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
<!-- Not strictly necessary, because Ant does the compilation, but at least attempts to keep it in sync with Maven -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>add-precompiled-jsp-java-sources</id>
<phase>generate-sources</phase>
<goals><goal>add-source</goal></goals>
<configuration>
<sources>
<source>${project.basedir}/generated-sources/jspc/java</source>
</sources>
</configuration>
</execution>
<execution>
<id>add-precompiled-jsp-resources</id>
<phase>generate-resources</phase>
<goals><goal>add-resource</goal></goals>
<configuration>
<resources>
<resource>
<directory>${project.basedir}/generated-sources/jspc/resources</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
Based on the excellent answer of paulcm I came up with my own solution as the above solution didn't work for me and I couldn't track down the error. Maybe the answer above is outdated for tomcat9. Or it had some problem with multi-module setup. However: All credits belong to paulcm
This is only the compile time solution.
Add these two plugins to your pom.xml
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jspc-maven-plugin</artifactId>
<version>9.4.15.v20190215</version>
<executions>
<execution>
<id>jspc</id>
<goals>
<goal>jspc</goal>
</goals>
<configuration>
<mergeFragment>true</mergeFragment>
<sourceVersion>1.8</sourceVersion>
<targetVersion>1.8</targetVersion>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<webXml>${project.basedir}/target/web.xml</webXml>
</configuration>
</plugin>
Add an empty web.xml file
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0"
metadata-complete="true">
<session-config>
<cookie-config>
</cookie-config>
</session-config>
</web-app>
Add a Registry
import org.apache.tomcat.util.descriptor.web.ServletDef;
import org.apache.tomcat.util.descriptor.web.WebXml;
import org.apache.tomcat.util.descriptor.web.WebXmlParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.xml.sax.InputSource;
import javax.servlet.ServletRegistration;
import java.io.InputStream;
import java.util.Map;
#Configuration
public class PreCompileJspRegistry {
private Logger logger = LoggerFactory.getLogger(this.getClass());
#Bean
public ServletContextInitializer registerPreCompiledJsps() {
return servletContext -> {
InputStream inputStream = servletContext.getResourceAsStream("/WEB-INF/web.xml");
if (inputStream == null) {
logger.info("Could not read web.xml");
return;
}
try {
WebXmlParser parser = new WebXmlParser(false, false, true);
WebXml webXml = new WebXml();
boolean success = parser.parseWebXml(new InputSource(inputStream), webXml, false);
if (!success) {
logger.error("Error registering precompiled JSPs");
}
for (ServletDef def : webXml.getServlets().values()) {
logger.info("Registering precompiled JSP: {} = {} -> {}", def.getServletName(), def.getServletClass());
ServletRegistration.Dynamic reg = servletContext.addServlet(def.getServletName(), def.getServletClass());
reg.setLoadOnStartup(99);
}
for (Map.Entry<String, String> mapping : webXml.getServletMappings().entrySet()) {
logger.info("Mapping servlet: {} -> {}", mapping.getValue(), mapping.getKey());
servletContext.getServletRegistration(mapping.getValue()).addMapping(mapping.getKey());
}
} catch (Exception e) {
logger.error("Error registering precompiled JSPs", e);
}
};
}
}
A comment for "At server start time" outlined above: the servlet you create will by default be in development mode if the application is packaged in an executable jar, so you if you use it in production mode, you should also set development = false ++ to prevent the jsps from being compiled again:
reg.setInitParameter("genStringAsCharArray", "true");
reg.setInitParameter("trimSpaces", "true");
reg.setInitParameter("development", "false");

How to use weaven with aspectJ in compiletime in spring project

We are using Spring and we used Spring AOP. Due to the nature of Spring AOP which uses Proxy we reached the limitation of it when tring to warp join point on call inside a call.
i.e
aspect on B execution will not run if A is being call
public void A(){
B()
}
public void B(){
}
In order to solves this issue we are using ApsectJ weaven in compile time.
Which is work good. But then, the issue is make it play nice with Spring Bean i.e let the Autowired work in side the aspect class.
Pom.xml Maven plugin
<!-- AspectJ configuration -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.7</version>
<configuration>
<complianceLevel>1.8</complianceLevel>
<source>1.8</source>
<target>1.8</target>
<showWeaveInfo>true</showWeaveInfo>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
EDIT
duplicate of Spring autowired bean for #Aspect aspect is null
info on how to get aspectj to work with maven
Use AspectJ in compile time and make sure spring autowired magic will work
According to the AspectJ doc aspectOf Chapter. In order to some module to known that aspect is an aspect of something one should use aspectOf. Spring has the feature
<bean id="a" class="com.someinterface.A" factory-method="aspectOf"></bean>
This will result the A of above to be a Spring Bean and as a bonus Spring will know that this is an aspect of some other code. This is enough for Spring to use the Autowire magic inside of an aspect.
NOTE that using aspectOf requires xml configuration. I tried to get the same result with #Configurable but it did not work. if some one has some info on that it will great. :)
Bonus - Use Spring AOP proxy for aspect(in run time)
Set spring to scan #Aspect and make it a spring bean
<context:component-scan base-package="com.centure" >
<context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/>
</context:component-scan>
in this case every thing will work out of the box
private SomeService service;
public SomeService getService() {
return service;
}
#Autowired
public void setService(SomeService) {
this.service = service;
}
#Aspect
public class myAspect {
#Pointcut("execution(public * com.myinterface.save(..))")
public void save() {
}
#Around("myAspect () && args(thearg)")
public Object doBasicProfiling(ProceedingJoinPoint pjp, TheObject thearg)
throws Throwable {
Object retVal = null;
try {
retVal = pjp.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
return retVal;
}

Resources