I am trying to serialize JAXB annotated class with Jackson using RESTEasy. By default ResteasyJacksonProvider is configured to use JACKSON annotation only. Is there a way to configure ResteasyJacksonProvider to use JAXB annotation using spring? There are couple of programmatic ways but would prefer if there is some spring configuration.
Couple of ways I am thinking of
Use ContextResolver for ObjectMapper type to return ObjectMapper configured to use JaxbAnnotationIntrospector instead of JacksonAnnotationIntrospector.
Extend ResteasyJacksonProvider and pass JAXB annotation during construction.
Any other way?
Well the first option of using ContextResolver works but I still think there should be an easier way to do this just by some configuration.
You can get this from the configuration only, no need to program anything special.
Here's how to:
First set your configuration right, I use Jackson + JAXB, both set under ContentNegotiatingViewResolver bean:
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="order" value="1"/>
<property name="mediaTypes">
<map>
<entry key="xml" value="application/xml" />
<entry key="json" value="application/json" />
</map>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
<property name="marshaller">
<oxm:jaxb2-marshaller id="marshaller">
<oxm:class-to-be-bound name="com.shay.dashboard.data.structure.page.PageObject" />
<oxm:class-to-be-bound name="com.shay.dashboard.data.structure.tab.TabObject" />
<oxm:class-to-be-bound name="com.shay.dashboard.data.structure.section.SectionObject" />
<oxm:class-to-be-bound name="com.shay.dashboard.data.structure.element.nonembedded.ElementObject"/>
<oxm:class-to-be-bound name="com.shay.dashboard.data.structure.element.embedded.EmbeddedElementObject"/>
<oxm:class-to-be-bound name="com.shay.dashboard.data.structure.chart.common.ChartManager"/>
</oxm:jaxb2-marshaller>
</property>
</bean>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"/>
</list>
</property>
</bean>
Notice that under the marshaller I set the oxm:class-to-be-bound - those are the classes to be bound by JAXB.
Now for the module, I used ordinary annotation package (javax.xml.bind.annotation), non marshaller specific. Jackson Json and JAXB both know how to read it.
For example:
#XmlAccessorType(XmlAccessType.NONE)
#XmlRootElement(name="page")
public class PageObject implements ComponentTypeObject{
#XmlAttribute(name="name")
private String name;
#XmlAttribute(name="id",required=true)
private String id;
#XmlElements({#XmlElement(name="tab", type=TabXmlAdapter.class)})
private List<TabXmlAdapter> tabRef;
Finally the controller for your MVC needs to return a model and view:
#RequestMapping(value="/get_page", method = RequestMethod.GET)
public ModelAndView initPage()
{
ModelAndView mav = null;
try
{
PageObject myPage = (PageObject) Utilities.getUtilities().loadObjectFromFile(XmlComponentType.page);
mav = new ModelAndView("page","page",myPage);
}
catch (Exception e)
{
e.getMessage();
}
return mav;
}
Now while calling your URL ending with .json you'd get the JSON representation, and with .xml - and XML. Both are translated by the viewer, provided you gave the correct mapping when annotating the module.
Related
is it possible to create a date condition for promotion in hybris?
I am trying to do this implementation. my first problem is how to map the parameter value
<bean id="dateRuleParameterValueMapperDefinition" class="de.hybris.platform.ruleengineservices.rule.strategies.impl.RuleParameterValueMapperDefinition">
<property name="mapper" ref="dateRuleParameterValueMapper" />
<property name="type" value="java.util.Date" />
</bean>
in this mapping, I have an exception that the type is not supported (Caused by: de.hybris.platform.ruleengineservices.rule.strategies.RuleParameterValueMapperException:)
if so, can I resolve this error .. is it possible to create a date condition in the RuleConditionTranslator?
hybris version: 6.5
If you want to add any new RuleParameterValueMapperDefinition, you have to implement 'RuleParameterValueMapper' and override 'toString' and 'fromString' methods in your mapper implementation.
public class MediaTypeRuleParameterValueMapper implements RuleParameterValueMapper<MediaModel>
{
#Resource
MediaService mediaService;
#Override
public String toString(final MediaModel mediaModel)
{
Preconditions.checkArgument(Objects.nonNull(mediaModel), "mediaModel must not be null!");
return mediaModel.getCode();
}
#Override
public MediaModel fromString(final String mediaCode)
{
try
{
return mediaService.getMedia(mediaCode);
}
catch (UnknownIdentifierException e)
{
e.message()
}
return null;
}
}
Now create a custom mapper definition (RuleParameterValueMapperDefinition)
<bean id="mediaTypeRuleParameterValueMapper" class="com.hybris.MediaTypeRuleParameterValueMapper"/>
<bean id="mediaTypeRuleParameterValueMapperDefinition" class="de.hybris.platform.ruleengineservices.rule.strategies.impl.RuleParameterValueMapperDefinition">
<property name="mapper" ref="mediaTypeRuleParameterValueMapper"/>
<property name="type" value="ItemType(Media)"/>
</bean>
Now you are ready to use
RuleConditionDefinitionParameter.type=ItemType(Media)
I don't believe that you need to map a date in that way, it should be treated the same as a String or Integer. So for reference look at the way any of the String or Integer parameters are handled.
My basis for saying this is the following from ruleengineservices-spring-rule.xml:
<alias name="defaultRuleParameterSupportedTypes" alias="ruleParameterSupportedTypes" />
<util:set id="defaultRuleParameterSupportedTypes" value-type="java.lang.String">
<value>java.lang.Boolean</value>
<value>java.lang.Character</value>
<value>java.lang.String</value>
<value>java.lang.Byte</value>
<value>java.lang.Short</value>
<value>java.lang.Integer</value>
<value>java.lang.Long</value>
<value>java.lang.Float</value>
<value>java.lang.Double</value>
<value>java.math.BigInteger</value>
<value>java.math.BigDecimal</value>
<value>java.util.Date</value>
<value>java.lang.Enum</value>
<value>java.util.List</value>
<value>java.util.Map</value>
</util:set>
I have a Spring 3.2.11 and Webflow 2.4.0 app using JSF2 for view rendering.
One of my pages uses a view-state model bean for validation but when the validatePasswordChange method is called, the bean properties have not been autowired so I get a NPE. I don't understand why they're null!?
Thank you for any suggestions.
Here's my bean validation method. Why is the passwordService property null?
public void validatePasswordChange(ValidationContext context) {
MessageContext messages = context.getMessageContext();
if (!confirmPassword.equals(newPassword)) {
messages.addMessage(new MessageBuilder().error()
.source("confirmPassword")
.defaultText(
this.getMessage("kyn.password.change.validation.noMatch"))
.build());
};
List<String> validationMessages = passwordService
.validatePasswordPolicyCompliance(getUsername(),
newPassword);
if (validationMessages != null) {
for (String message : validationMessages) {
messages.addMessage(new MessageBuilder().error()
.source("confirmPassword")
.defaultText(message).build());
}
}
}
Here's a snippet from my flow.xml. I'm inserting passwordUpdateBean into the flowScope in the on-start and expecting the model attribute to use it:
<on-start>
<evaluate expression="passwordUpdateBean" result="flowScope.passwordUpdateBean"></evaluate>
</on-start>
<view-state id="passwordChange" model="passwordUpdateBean">
<transition on="proceed" to="update"/>
<transition on="cancel" to="redirectCancel" validate="false"/>
</view-state>
And here's my bean config xml:
<bean id="passwordUpdateBean"
class="com.xyz.PasswordUpdateBean"
scope="prototype"
parent="abstractWebBean">
<property name="passwordService" ref="passwordManagementService"/>
<property name="appUserDetailsService" ref="appUserDetailsService"/>
<property name="autoLoginAfterEnrollment" value="true"/>
<property name="usernamePasswordAuthenticationProvider" ref="usernamePasswordAuthenticationProvider"/>
</bean>
beans will NOT auto wire inside your flow definitions. You have get have to explicitly retrieve the bean into the flow definition.
Note #Service class annotations are automatically accessible in flow files (i.e <evaluate expression="myService.getPasswordUpdateBean()" result="flowScope.passwordUpdateBean"/>)
<on-start>
<evaluate expression="....getPasswordUpdateBean()" result="flowScope.passwordUpdateBean"></evaluate>
<!-- where '....' = either #service class or some other obj that holds a reference to the bean you seek -->
</on-start>
I would like to use the new Rest DSL in Apache Camel 2.14 to create a rest interface. I would like to use the Jetty component and I have a basic example setup like this:
Spring Security Configuration
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:spring-security="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
http://camel.apache.org/schema/spring-security http://camel.apache.org/schema/spring-security/camel-spring-security.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
<spring-security:http auto-config="true" use-expressions="true" >
<spring-security:intercept-url pattern="/**" access="isFullyAuthenticated()"/>
<spring-security:http-basic></spring-security:http-basic>
</spring-security:http>
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
<property name="allowIfAllAbstainDecisions" value="true"/>
<property name="decisionVoters">
<list>
<bean class="org.springframework.security.access.vote.RoleVoter"/>
</list>
</property>
</bean>
<spring-security:authentication-manager alias="authenticationManager">
<spring-security:authentication-provider user-service-ref="userDetailsService"/>
</spring-security:authentication-manager>
<spring-security:user-service id="userDetailsService">
<spring-security:user name="admin" password="admin" authorities="ROLE_USER, ROLE_ADMIN"/>
<spring-security:user name="user" password="user" authorities="ROLE_USER"/>
</spring-security:user-service>
<authorizationPolicy id="admin" access="ROLE_ADMIN"
authenticationManager="authenticationManager"
accessDecisionManager="accessDecisionManager"
xmlns="http://camel.apache.org/schema/spring-security"/>
<authorizationPolicy id="user" access="ROLE_USER"
xmlns="http://camel.apache.org/schema/spring-security"/>
Camel Route Configuration
restConfiguration().component("jetty").host("0.0.0.0").port(24999).bindingMode(RestBindingMode.json).dataFormatProperty("prettyPrint", "true");
rest("address").description("Contains services for addresses").
consumes("application/json").
produces("application/json").
get().
route().policy("admin").
to("bean:restAddressApi?method=queryAddress").endRest();
When I try to access this protected URL using wget with this:
wget --http-user=admin --http-password=admin http://localhost:24999/address/
Then I get this error in the console:
org.apache.camel.CamelAuthorizationException: Cannot find the Authentication instance.. Exchange[Message: [Body is null]]
at org.apache.camel.component.spring.security.SpringSecurityAuthorizationPolicy.beforeProcess(SpringSecurityAuthorizationPolicy.java:72)
at org.apache.camel.component.spring.security.SpringSecurityAuthorizationPolicy$AuthorizeDelegateProcess.process(SpringSecurityAuthorizationPolicy.java:120)
at org.apache.camel.util.AsyncProcessorConverterHelper$ProcessorToAsyncProcessorBridge.process(AsyncProcessorConverterHelper.java:61)
at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:416)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:191)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:118)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:80)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:191)
at org.apache.camel.component.jetty.CamelContinuationServlet.service(CamelContinuationServlet.java:150)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:668)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:684)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:503)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1086)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:429)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1020)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116)
at org.eclipse.jetty.server.handler.ResourceHandler.handle(ResourceHandler.java:406)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116)
at org.eclipse.jetty.server.Server.handle(Server.java:370)
at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:494)
at org.eclipse.jetty.server.AbstractHttpConnection.headerComplete(AbstractHttpConnection.java:971)
at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.headerComplete(AbstractHttpConnection.java:1033)
at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:644)
at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:235)
at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:82)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:696)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:53)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543)
at java.lang.Thread.run(Thread.java:745)
What am I missing in my config to get this working?
Two options.
You can use basic auth with jetty rest DSL. I just spent some time working with basic auth, a jetty rest DSL service, and camel 2.15. I wrote up my experiences here: http://www.mooreds.com/wordpress/archives/2065 . I found the camel-jetty wiki page a bit out of date, full code here: https://github.com/mooreds/camel-rest-jetty-auth
You can use spring security (at least with version 2.15.2 of camel and 4.0.1.RELEASE of spring security, which is what I am using). To do so, you need to make sure you create a processor class, as outlined here: http://camel.apache.org/spring-security.html#SpringSecurity-Authentication and put it in front of every route before you call the policy. You also need to create an exception handler to present a nice message to an unauthorized user--here's what I did in my java routebuilder: onException(org.apache.camel.CamelAuthorizationException.class).handled(true).transform(simple("Access Denied with the Policy of ${exception.policyId} !")).setHeader(Exchange.HTTP_RESPONSE_CODE, simple("401"));
Here is how I solved it using Apache Camel 2.15.2. I use this backend together with an AngularJS frontent where I use an httpInterceptor to add the authenitcation header.
I use JWT to store a tenantId in the authorization header. This tenantId is used together with Hibernate and its Multi Tenancy Support.
Front end login controller, using AngularJs and written in TypeScript:
/// <reference path="../reference.ts"/>
module Controllers {
export class Credentials {
username:string;
password:string;
}
export interface ILoginControllerScope extends ng.IScope {
credentials:Credentials;
login:()=>void;
}
export class LoginController {
private _scope:ILoginControllerScope;
static $inject = ['$scope', '$http', 'UserService', '$location'];
constructor($scope:ILoginControllerScope, $http:ng.IHttpService, UserService:UserService, $location:ng.ILocationService) {
this._scope = $scope;
$scope.credentials = new Credentials();
$scope.login = ()=> {
$http.post('/api/authenticate', $scope.credentials)
.success(function (data:string, status:any, headers:any, config:any) {
// Remove all " characters from string.
data = data.replace(/"/gi, '');
UserService.setSecurityToken(data);
$location.path('/');
})
.error(function (data:any, status:any, headers:any, config:any) {
});
}
}
}
}
#Override
public void process(Exchange exchange) throws Exception {
Map<String, String> credentials = exchange.getIn().getBody(HashMap.class);
String username = credentials.get("username");
String password = credentials.get("password");
// Login logic that returns object() containing user info
exchange.getIn().setBody(jwtService.generateToken(tenantConfiguration));
}
}
}
This is the class JwtService that is responsible for creating a JWT Token:
package com.me.services;
import com.me.TenantConfiguration;
import com.google.common.collect.Maps;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.security.SecureRandom;
import java.util.Map;
import java.util.Random;
#Service
public class JwtService {
public static final String TENANT_ID = "tenant_id";
public static final String ROLE = "role";
#Value("${jwt.subject}")
private String jwtSubject;
private byte[] signingKey;
private SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
public SignatureAlgorithm getSignatureAlgorithm() {
return signatureAlgorithm;
}
public byte[] getSigningKey() {
if (this.signingKey == null) {
// Generate new signingKey
Random random = new SecureRandom();
signingKey = new byte[64];
random.nextBytes(signingKey);
}
return this.signingKey;
}
public String getJwtSubject() {
return jwtSubject;
}
public String generateToken(TenantConfiguration tenantConfiguration){
Map<String, Object> claims = Maps.newHashMap();
claims.put(TENANT_ID, tenantConfiguration.getSessionId());
String token = Jwts.builder().setSubject(this.getJwtSubject()).setClaims(claims).signWith(this.getSignatureAlgorithm(), this.getSigningKey()).compact();
return token;
}
}
To use this in a route I define it like this:
rest("api/messages").description("Restful API for messages").
get().id("GetMessages").route().to("springSecurityContextLoader").policy(authorizationPolicy).to("bean:restMessageApi?method=getAllMessages").endRest().
SpringSecurityContextloader
#Service
public class SpringSecurityContextLoader implements Processor {
#Inject
private JwtService jwtService;
#Override
public void process(Exchange exchange) throws Exception {
String authorization = exchange.getIn().getHeader("Authorization", String.class);
Jwt jwt = Jwts.parser().setSigningKey(jwtService.getSigningKey()).parse(authorization);
Map<String, Object> claims = (Map<String, Object>) jwt.getBody();
String tenantId = claims.get(JwtService.TENANT_ID).toString();
Authentication authentication = new PreAuthenticatedAuthenticationToken(tenantId, "something", Lists.newArrayList(new SimpleGrantedAuthority("ROLE_USER")));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
Taken from https://camel.apache.org/jetty.html
Jetty handlers and security configuration
You can configure a list of Jetty handlers on the endpoint, which can be useful for enabling advanced Jetty security features. These handlers are configured in Spring XML as follows:
<-- Jetty Security handling -->
<bean id="userRealm" class="org.mortbay.jetty.plus.jaas.JAASUserRealm">
<property name="name" value="tracker-users"/>
<property name="loginModuleName" value="ldaploginmodule"/>
</bean>
<bean id="constraint" class="org.mortbay.jetty.security.Constraint">
<property name="name" value="BASIC"/>
<property name="roles" value="tracker-users"/>
<property name="authenticate" value="true"/>
</bean>
<bean id="constraintMapping" class="org.mortbay.jetty.security.ConstraintMapping">
<property name="constraint" ref="constraint"/>
<property name="pathSpec" value="/*"/>
</bean>
<bean id="securityHandler" class="org.mortbay.jetty.security.SecurityHandler">
<property name="userRealm" ref="userRealm"/>
<property name="constraintMappings" ref="constraintMapping"/>
</bean>
I am trying to put a key as String , value as List Intervals> in the cache and I am getting the below error. I have a put method in dao as generalised as object,object> so it can be used for difference cache
Input
[MAC4, [com.xx.Interval#1bccacc7]]
[MAC3, [com.xx.Interval#754b3232]]
[MAC1, [com.xx.Interval#78cf9e78, com.xx.Interval#6ad163f]]
MAC* is the key and List of Interval Objects are values.
Code:
griddao.put("intervals",tuple.getValue(0),tuple.getValue(1));
In griddao
public void put(String cacheName, Object key, Object value) throws GridException {
GridCache<Object, Object> cache = caches.get(cacheName);
if ( cache != null ) {
cache.put(key, value);
}
else {
LOG.error( "Cache is null");
}
It looks like you forgot to attach the actual error you got. Please provide full exception trace.
For now you can check whether Interval class implements Serializable. If it doesn't and you can't change it, configure marshaller not to require Serializable interface, like this:
<bean id="grid.cfg" class="org.gridgain.grid.GridConfiguration">
...
<property name="marshaller">
<bean class="org.gridgain.grid.marshaller.optimized.GridOptimizedMarshaller">
<property name="requireSerializable" value="false"/>
</bean>
</property>
...
</bean>
1) Is there a way to unmarshall MTOM message using Camel Spring-WS component?
2) I tried with Camel JAXB dataformat. It didn't work. Datahandler doesn't have any content. Does JAXB dataformat support MTOM?
<dataFormats>
<jaxb id="jaxb" contextPath="com.mycompany.hr.jaxb"/>
</dataFormats>
<route>
<from uri="spring-ws:rootqname:{http://mycompany.com/hr/schemas}HolidayRequest?endpointMapping=#endpointMapping" />
<unmarshal ref="jaxb"/>
<process ref="testProcessor" />
</route>
3) I thought MTOM is not enabled in JAXB dataformat. So I created a custom dataformat using MTOM enabled JAXB2Marshaller. But still facing the same issue.
import java.io.InputStream;
import java.io.OutputStream;
import javax.xml.transform.Source;
import org.apache.camel.Exchange;
import org.apache.camel.spi.DataFormat;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
public class MtomDataFormat implements DataFormat {
public void marshal(Exchange arg0, Object arg1, OutputStream arg2)
throws Exception {
// TODO Auto-generated method stub
}
public Object unmarshal(Exchange exchange, InputStream is) throws Exception {
Source source = exchange.getContext().getTypeConverter().mandatoryConvertTo(Source.class, is);
Jaxb2Marshaller mar = new Jaxb2Marshaller();
mar.setContextPath("com.mycompany.hr.jaxb");
mar.setMtomEnabled(true);
return mar.unmarshal(source);
}
}
Spring configuration
<bean id="endpointMapping"
class="org.apache.camel.component.spring.ws.bean.CamelEndpointMapping">
</bean>
<bean id="testProcessor" class="TestProcessor" />
<bean id="mtomDataFormat" class="MtomDataFormat" />
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="spring-ws:rootqname:{http://mycompany.com/hr/schemas}HolidayRequest?endpointMapping=#endpointMapping" />
<unmarshal ref="mtomDataFormat"/>
<process ref="testProcessor" />
</route>
</camelContext>