Spring CXF configuration without xml - java

I want to create a RESTfull web service using Spring + CXF without XML bean configuration. How can I convert the below XML based configuration into Java ?
applicationBean.xml
<jaxrs:server id="employeeService" address="/employeeservices">
<jaxrs:providers>
<bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
</jaxrs:providers>
<jaxrs:serviceBeans>
<ref bean="cxfServiceImpl" />
</jaxrs:serviceBeans>
<jaxrs:extensionMappings>
<entry key="xml" value="application/xml" />
<entry key="json" value="application/json" />
</jaxrs:extensionMappings>
</jaxrs:server>
Spring CXF configuration
#Configuration
public class AppConfig {
//Code for CXF need to be here
}

if you are using spring-boot, here is the simplest way.
#Import(SpringComponentScanServer.class)
#Configuration
public class KpCxfConfiguration {
#Bean
public ServletRegistrationBean servletRegistrationBean(ApplicationContext context) {
return new ServletRegistrationBean(new CXFServlet(), "/api/*");
}
}
Note: your service classes needs to be annotated with #Path annotation
And if you are using non-spring boot application you can define servlet mapping in web.xml

Related

Looking for a simple, xml-oriented way of connecting Spring-Integration http inbound gateways to Jetty

I'm looking for a lighter way of unit-testing my spring-integration-http gateways than by using SpringBootTest. I'd like to see if I can attach my spring-integration handlers to Jetty directly.
As a trivial example gateway, I'm using this gateway and chain/channel:
<!-- test-app/service.xml -->
<beans xmlns="http://www.springframework.org/schema/beans"
...
<int-http:inbound-gateway
request-channel="requestChannel"
supported-methods="GET"
path="/test">
<int-http:request-mapping produces="application/json" />
</int-http:inbound-gateway>
<int:channel id = "requestChannel" />
<int:chain input-channel = "requestChannel" >
<int:transformer expression="'{ "today" : "JUBILEE" }'" />
</int:chain>
</beans>
I can wrap this into a SpringBoot application and then test it using rest-assured and SpringBootTest. This works fine but is fairly slow and heavy-weight:
#SpringBootApplication
#ImportResource({"classpath:test-app/service.xml"})
public class JettyIntSpringBootApp {
public static void main(String[] args) {
SpringApplication.run(JettyIntSpringBootApp.class, args);
}
}
#RunWith(SpringRunner.class)
#SpringBootTest(classes = JettyIntSpringBootApp.class,
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class UsingSpringBootTest {
#LocalServerPort
int localServerPort;
#Test
public void can_get_spring_boot_server() {
callGet("test")
.then()
.assertThat().statusCode(200)
.assertThat().body("today", equalTo("JUBILEE"));
}
private Response callGet(final String resource) {
return RestAssured
.given(getMinimalSpecBuilder())
.get(resource);
}
private RequestSpecification getMinimalSpecBuilder() {
return new RequestSpecBuilder()
.setPort(localServerPort)
.setBaseUri("http://localhost:" + localServerPort + "/")
.setContentType(ContentType.JSON)
.setAccept(ContentType.JSON)
.build();
}
}
To try to get the equivalent to run directly in Jetty without the spring-boot overhead, I've created a separate context for the Jetty server, as described in the eclipse documentation: https://www.eclipse.org/jetty/documentation/jetty-9/index.html#framework-jetty-spring
<beans> <!-- test-app/jetty.xml -->
<bean id="contexts" class="org.eclipse.jetty.server.handler.ContextHandlerCollection" />
<bean id="server" name="Main" class="org.eclipse.jetty.server.Server" init-method="start" destroy-method="stop">
<constructor-arg>
<bean id="threadPool" class="org.eclipse.jetty.util.thread.QueuedThreadPool">
<property name="minThreads" value="10"/>
<property name="maxThreads" value="50"/>
</bean>
</constructor-arg>
<property name="connectors">
<list>
<bean id="connector" class="org.eclipse.jetty.server.ServerConnector">
<constructor-arg ref="server"/>
<property name="port" value="9091"/>
</bean>
</list>
</property>
<property name="handler">
<bean id="handlers" class="org.eclipse.jetty.server.handler.HandlerCollection">
<property name="handlers">
<list>
<ref bean="contexts"/>
<bean id="defaultHandler" class="org.eclipse.jetty.server.handler.DefaultHandler"/>
</list>
</property>
</bean>
</property>
</bean>
</beans>
I then use SpringRunner to load up the Jetty context configuration with original SpringIntegration service configuration containing the http inbound gateway and chain:
#RunWith(SpringRunner.class)
#ContextConfiguration(locations = { "classpath:test-app/jetty.xml",
"classpath:test-app/service.xml" } )
public class JettyServerTest {
#Test
public void can_get_jetty_server() {
callGet("test")
.then()
.log().all()
.assertThat().statusCode(200)
.assertThat().body("today", equalTo("JUBILEE"));
}
private Response callGet(final String resource) {
return RestAssured
.given(getMinimalSpecBuilder())
.get(resource);
}
private RequestSpecification getMinimalSpecBuilder() {
return new RequestSpecBuilder()
.setPort(9091)
.setBaseUri("http://localhost:" + 9091 + "/")
.setContentType(ContentType.JSON)
.setAccept(ContentType.JSON)
.build();
}
}
This second test fails. The SpringIntegration context is loaded and the Jetty server is also loaded and allows the RestAssured client to connect. However, the "servlet handler" for SpringIntegration is not loaded into the Jetty server, hence the call to Jetty returns a 404 "Resource not found". Jetty is not configured with the SpringIntegration gateway handler.
I'm thinking that there must be a simple way of including either the SpringIntegration DispatcherServlet or the HttpRequestHandlingMessagingGateway as a handler in the Jetty server context, probably via the contexts bean of the jetty.xml configuration. I've tried a number of avenues but no success, hence my post. All pointers appreciated.

Integrate Multiple Shiro Realms into a Spring Boot environment Java

I have a xml based Apache Shiro SecurityManager and few custom realms (They extend build in realms). I am trying to migrate to Spring Boot, which is mostly annotation based.
I want to configure ALL realms into the security manager easily.Currently, I am able to do it by creating a ShiroConfig.java (annotated by #Configuration) , manually creating the object of each realm in the ShiroConfig and adding it under DefaultWebSecurityManager.setRealms(Collection).
Is there any other way, by which same thing can be achieved by annotation, where I annotate each Realm ,saying it's a realm and all of them will be added under security manager at runtime ?
Current xml configuration
<bean id="securityManager" class="com.abc.xyz.SecurityManager">
<property name="realms">
<set>
<ref component-id="Realm_1”/>
<ref component-id="Realm_2” />
<ref component-id="Realm_3” />
<ref component-id="Realm_4” />
</set>
</property>
</bean>
<bean id="Realm_1" class="com.abc.xyz.Realm_1”>
</bean>
<bean id="Realm_2" class="com.abc.xyz.Realm_2”>
</bean>
<bean id="Realm_3” class="com.abc.xyz.Realm_3”>
</bean>
<bean id="Realm_4” class="com.abc.xyz.Realm_4”>
</bean>
Current Spring boot code [which I don't want to repeat for each realm]
#Bean(name="securityManager")
public DefaultWebSecurityManager securityManager() {
DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
manager.setRealm(userRealm());
manager.setSessionManager(defaultWebSessionManager());
return manager;
}
#Bean
#DependsOn(value="lifecycleBeanPostProcessor")
public Realm_1 userRealm() {
Realm_1 userRealm = new Realm_1();
return userRealm;
}
Shiro 1.4 is hot off the presses, we are working on getting the site updated now. But take a look at the examples, you can just inject your Realms in Spring and Spring-Boot.
https://github.com/apache/shiro/blob/master/support/spring/src/main/java/org/apache/shiro/spring/config/ShiroConfiguration.java#L44-L48
https://github.com/apache/shiro/blob/master/samples/spring/src/main/java/org/apache/shiro/samples/spring/CliApp.java#L46-L56

Annotation based Spring Activiti ProcessEngine

I am quite new to Spring and Activiti. I'm developing annotation based Spring web application with embedded Activiti engine. I have some services implemented, SubscriptionService is one of them. In one process I call that service as bean with:
activiti:expression="${subscriptionService.getContacts(publisherCode, contactType)}"
Service:
#Service
#Transactional
public class DBSubscriptionService implements SubscriptionService {
...
}
I have separated test module and web module. Test module loads context from activiti.cfg.xml with
#ContextConfiguration("classpath:activiti.cfg.xml")
and it is:
<bean id="processEngineConfiguration"
class="org.activiti.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration">
<property name="databaseType" value="h2" />
<property name="databaseSchemaUpdate" value="true" />
<property name="jobExecutorActivate" value="false" />
<property name="history" value="full" />
<property name="mailServerPort" value="2025" />
</bean>
<bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
<property name="processEngineConfiguration" ref="processEngineConfiguration" />
</bean>
<bean id="repositoryService" factory-bean="processEngine"
factory-method="getRepositoryService" />
<bean id="runtimeService" factory-bean="processEngine"
factory-method="getRuntimeService" />
<bean id="taskService" factory-bean="processEngine"
factory-method="getTaskService" />
<bean id="historyService" factory-bean="processEngine"
factory-method="getHistoryService" />
<bean id="managementService" factory-bean="processEngine"
factory-method="getManagementService" />
<bean id="identityService" factory-bean="processEngine"
factory-method="getIdentityService" />
<bean id="formService" factory-bean="processEngine"
factory-method="getFormService" />
<context:component-scan base-package="cz.muni.fi.cep" />
<context:annotation-config />
In test module, everything works fine. But in web module when it should call subscriptionService Bean it throws:
Unknown property used in expression: ${subscriptionService.getContacts(publisherCode, contactType)}
Caused by: org.activiti.engine.impl.javax.el.PropertyNotFoundException: Cannot resolve identifier 'subscriptionService'
at org.activiti.engine.impl.juel.AstIdentifier.eval(AstIdentifier.java:83)
at org.activiti.engine.impl.juel.AstMethod.invoke(AstMethod.java:79)
at org.activiti.engine.impl.juel.AstMethod.eval(AstMethod.java:75)
at org.activiti.engine.impl.juel.AstEval.eval(AstEval.java:50)
at org.activiti.engine.impl.juel.AstNode.getValue(AstNode.java:26)
at org.activiti.engine.impl.juel.TreeValueExpression.getValue(TreeValueExpression.java:114)
at org.activiti.engine.impl.delegate.ExpressionGetInvocation.invoke(ExpressionGetInvocation.java:33)
at org.activiti.engine.impl.delegate.DelegateInvocation.proceed(DelegateInvocation.java:37)
at org.activiti.engine.impl.delegate.DefaultDelegateInterceptor.handleInvocation(DefaultDelegateInterceptor.java:25)
at org.activiti.engine.impl.el.JuelExpression.getValue(JuelExpression.java:48)
... 363 more
So I understand problem is that Process engine does not use right application context, because subscription service is autowired to other classes just fine. But I don't know how to fix it.
Web module is purely annotation based:
#EnableAutoConfiguration
#Configuration
#EntityScan(basePackages = "cz.muni.fi.cep")
#ComponentScan(basePackages = "cz.muni.fi.cep")
public class App extends WebMvcConfigurerAdapter {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
...
}
And Activiti configuration:
#Configuration
public class ActivitiConfig {
#Bean
public ProcessEngine processEngine(ProcessEngineConfigurationImpl pec, ApplicationContext applicationContext) throws Exception {
ProcessEngineFactoryBean pe = new ProcessEngineFactoryBean();
pe.setProcessEngineConfiguration(pec);
pe.setApplicationContext(applicationContext);
return pe.getObject();
}
#Bean
public ProcessEngineConfigurationImpl getProcessEngineConfiguration(
DataSource dataSource,
PlatformTransactionManager transactionManager,
ApplicationContext context) {
SpringProcessEngineConfiguration pec = new SpringProcessEngineConfiguration();
pec.setDataSource(dataSource);
pec.setDatabaseSchemaUpdate("true");
pec.setJobExecutorActivate(true);
pec.setHistory("full");
pec.setMailServerPort(2025);
pec.setDatabaseType("mysql");
pec.setTransactionManager(transactionManager);
pec.setApplicationContext(context);
return pec;
}
#Bean
public RuntimeService getRuntimeService(ProcessEngine processEngine) {
return processEngine.getRuntimeService();
}
...
}
Also, maybe order of context creation has somethong to do with this.
Everything looks OK, I believe it might be something as simple as the subscription service not being scanned (does it belong to package cz.muni.fi.cep?), or Spring assigning another name to the subscription service bean (i.e. dbSubscriptionService or dBSubscriptionService instead of just subscriptionService).
Try replacing #Service in DBSubscriptionService class by #Service("subscriptionService") and it should work.

Alternate to #XmlRootElement?

in process of exposing existing statefull service as a RESTfull service.
I do not want to make any changes to any existing java class.I have been able to configure other annotations such as #path, #GET using spring-config.xml
spring-config.xml
<!-- Inquiry Services -->
<bean id="retrieveContactHistoryBP" class="com.csc.fs.ws.contact.history.impl.RetrieveContactHistoryBPService"/>
<!-- Update Services -->
<bean id="startContactBP" class="com.csc.fs.ws.contact.impl.StartContactBPService"/>
<!-- REST services -->
<bean id="startContactBPRest" class="com.csc.fs.rest.contact.StartContactBP" scope="prototype" />
<bean id="retrieveContactHistoryBPRest" class="com.csc.fs.rest.contact.RetrieveContactHistoryBP" scope="prototype" />
<!-- Exposing beans as rest services -->
<jaxrs:server id="restServer" address="/rest/">
<jaxrs:model id="restModel">
<jaxrs:resource name="com.csc.fs.rest.contact.RetrieveContactHistoryBP" path="retrieveContactHistoryBP">
<jaxrs:operation name="retrieve" path="{partyId}" consumes="application/json" produces="application/json" verb="GET">
<jaxrs:param name="req" type="CONTEXT"/>
<jaxrs:param name="partyId" type="PATH"/>
</jaxrs:operation>
</jaxrs:resource>
<jaxrs:resource name="com.csc.fs.rest.contact.StartContactBP" path="startContactBP">
<jaxrs:operation name="startContact" path="/" consumes="application/json" produces="application/json" verb="PUT">
<jaxrs:param name="req" type="CONTEXT"/>
<jaxrs:param name="startContact" type="REQUEST_BODY"/>
</jaxrs:operation>
</jaxrs:resource>
</jaxrs:model>
<jaxrs:serviceBeans>
<!-- <ref bean="startContactBPRest"/> --> <!-- Instead configure above -->
<!-- <ref bean="retrieveContactHistoryBPRest"/> -->
</jaxrs:serviceBeans>
<jaxrs:extensionMappings>
<entry key="feed" value="application/atom+xml"/>
<entry key="json" value="application/json"/>
<entry key="xml" value="application/xml"/>
<entry key="html" value="text/html"/>
</jaxrs:extensionMappings>
<jaxrs:providers>
<ref bean="jaxbProvider"/>
<ref bean="jsonProvider" />
</jaxrs:providers>
</jaxrs:server>
The thing I am facing problem is with the #XmlRootElement. I have not been successful in configuring it through the xml.
And I get the following error when trying to access the REST service
org.apache.cxf.interceptor.Fault
org.apache.cxf.interceptor.AbstractFaultChainInitiatorObserver.onMessage(AbstractFaultChainInitiatorObserver.java:67)
org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:315)
org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:113)
org.apache.cxf.transport.servlet.ServletDestination.invoke(ServletDestination.java:105)
org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:461)
org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:188)
org.apache.cxf.transport.servlet.AbstractCXFServlet.invoke(AbstractCXFServlet.java:148)
org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:179)
org.apache.cxf.transport.servlet.AbstractHTTPServlet.doGet(AbstractHTTPServlet.java:108)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:159)
root cause
java.lang.NullPointerException
org.apache.cxf.jaxrs.model.wadl.WadlGenerator.handleOperation(WadlGenerator.java:310)
org.apache.cxf.jaxrs.model.wadl.WadlGenerator.handleResource(WadlGenerator.java:253)
org.apache.cxf.jaxrs.model.wadl.WadlGenerator.handleRequest(WadlGenerator.java:185)
org.apache.cxf.jaxrs.impl.RequestPreprocessor.checkMetadataRequest(RequestPreprocessor.java:189)
org.apache.cxf.jaxrs.impl.RequestPreprocessor.preprocess(RequestPreprocessor.java:82)
org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.processRequest(JAXRSInInterceptor.java:112)
org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.handleMessage(JAXRSInInterceptor.java:88)
org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:255)
org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:113)
org.apache.cxf.transport.servlet.ServletDestination.invoke(ServletDestination.java:105)
org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:461)
org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:188)
org.apache.cxf.transport.servlet.AbstractCXFServlet.invoke(AbstractCXFServlet.java:148)
org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:179)
org.apache.cxf.transport.servlet.AbstractHTTPServlet.doGet(AbstractHTTPServlet.java:108)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:159)
So, Is there a way to configure the information in the XmlRoot annotation externally, so we don’t have to add it to Java code?
From the Apache-cxf documentation on jaxrs-data-bindings:
Alternatively to using #XmlRootElement and Collection wrappers, one can
provide an Object factory which will tell JAXB how to marshal a given
type (in case of Collections - its template type). Another option is to
return/accept a JAXBElement directly from/in a given method.
Another option is to register one or more JAX-RS ContextResolver providers
capable of creating JAXBContexts for a number of different types. The
default JAXBElementProvider will check these resolvers first before
attempting to create a JAXBContext on its own.

CXF is ignoring Spring bean configuration

I have a web application which is exposing a rest web service by cxf jax-rs. In my application context file I have something like this:
...
<bean id="service" class="SomeClass">
<constructor-arg index="0">
<ref bean="bean1" />
</constructor-arg>
<constructor-arg index="1"
value="some value" />
</bean>
<jaxrs:server id="restContainer" address="/">
<jaxrs:serviceBeans>
<ref bean="service" />
</jaxrs:serviceBeans>
<jaxrs:providers>
<bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
</jaxrs:providers>
</jaxrs:server>
...
I also have a constructor in my service class that accepts those two parameters and initializes the service.
When I deploy my application, spring context loader is creating the service bean correctly and the correct constructor is getting called. The problem is when the first Rest request comes to service. Cxf Jax-rs is creating its own instance by "default constructor" and I will lose those two properties.
The same thing happens if I user property setters instead of constructor args. When I researched cxf jax-rs, none of the examples had a service which has some properties! Is there a reason for this or is this some implementation constraint by cxf?
Any ideas?

Categories