From efccdd821b68280ee3b73c8ef5cda121bc27f620 Mon Sep 17 00:00:00 2001 From: rfeng Date: Sat, 13 Nov 2010 17:42:16 +0000 Subject: Improve jaxb/json databindings and jsonrpc binding to better handle interfaces git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1034820 13f79535-47bb-0310-9956-ffa450edef68 --- .../binding-jsonrpc-runtime/META-INF/MANIFEST.MF | 1 + .../jsonrpc/provider/JSONRPCBindingInvoker.java | 48 ++-- .../binding/jsonrpc/provider/JSONRPCClient.java | 293 +++++++++++++++++++++ .../jsonrpc/provider/JSONRPCClientInvoker.java | 13 +- .../provider/JSONRPCReferenceBindingProvider.java | 19 +- .../sca/databinding/jaxb/JAXBContextHelper.java | 30 ++- .../modules/databinding-json/META-INF/MANIFEST.MF | 2 + .../sca/databinding/json/jackson/JSON2Object.java | 3 +- .../databinding/json/jackson/JacksonHelper.java | 83 ++++-- .../sca/databinding/json/jackson/Object2JSON.java | 9 +- 10 files changed, 444 insertions(+), 57 deletions(-) create mode 100644 sca-java-2.x/trunk/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JSONRPCClient.java (limited to 'sca-java-2.x') diff --git a/sca-java-2.x/trunk/modules/binding-jsonrpc-runtime/META-INF/MANIFEST.MF b/sca-java-2.x/trunk/modules/binding-jsonrpc-runtime/META-INF/MANIFEST.MF index 7c7b8e14a5..0ca3d9ef25 100644 --- a/sca-java-2.x/trunk/modules/binding-jsonrpc-runtime/META-INF/MANIFEST.MF +++ b/sca-java-2.x/trunk/modules/binding-jsonrpc-runtime/META-INF/MANIFEST.MF @@ -35,6 +35,7 @@ Import-Package: javax.security.auth.login, org.apache.tuscany.sca.runtime;version="2.0.0", org.jabsorb, org.jabsorb.client, + org.jabsorb.serializer, org.json, org.oasisopen.sca;version="2.0.0", org.oasisopen.sca.annotation;version="2.0.0" diff --git a/sca-java-2.x/trunk/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JSONRPCBindingInvoker.java b/sca-java-2.x/trunk/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JSONRPCBindingInvoker.java index ecca09dc92..3de6e57dda 100644 --- a/sca-java-2.x/trunk/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JSONRPCBindingInvoker.java +++ b/sca-java-2.x/trunk/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JSONRPCBindingInvoker.java @@ -26,9 +26,9 @@ import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.util.EntityUtils; import org.apache.tuscany.sca.assembly.EndpointReference; -import org.apache.tuscany.sca.binding.jsonrpc.JSONRPCBinding; import org.apache.tuscany.sca.databinding.json.JSONDataBinding; import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.invocation.DataExchangeSemantics; import org.apache.tuscany.sca.invocation.Invoker; import org.apache.tuscany.sca.invocation.Message; import org.json.JSONArray; @@ -39,18 +39,18 @@ import org.json.JSONObject; * * @version $Rev$ $Date$ */ -public class JSONRPCBindingInvoker implements Invoker { +public class JSONRPCBindingInvoker implements Invoker, DataExchangeSemantics { private EndpointReference endpointReference; private Operation operation; private String uri; - + private HttpClient httpClient; public JSONRPCBindingInvoker(EndpointReference endpointReference, Operation operation, HttpClient httpClient) { this.endpointReference = endpointReference; this.operation = operation; - this.uri = ((JSONRPCBinding) endpointReference.getBinding()).getURI(); - + this.uri = endpointReference.getBinding().getURI(); + this.httpClient = httpClient; } @@ -64,9 +64,9 @@ public class JSONRPCBindingInvoker implements Invoker { final String db = msg.getOperation().getWrapper().getDataBinding(); String req; if (!db.equals(JSONDataBinding.NAME)) { - - JSONObject jsonRequest = null;; + JSONObject jsonRequest = null; + ; Object[] args = null; try { // Extract the method @@ -87,7 +87,7 @@ public class JSONRPCBindingInvoker implements Invoker { } req = jsonRequest.toString(); } else { - req = (String)((Object[])msg.getBody())[0]; + req = (String)((Object[])msg.getBody())[0]; } StringEntity entity = new StringEntity(req, "UTF-8"); post.setEntity(entity); @@ -97,20 +97,20 @@ public class JSONRPCBindingInvoker implements Invoker { if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { //success try { - String entityResponse = EntityUtils.toString(response.getEntity()); + String entityResponse = EntityUtils.toString(response.getEntity()); if (!db.equals(JSONDataBinding.NAME)) { JSONObject jsonResponse = new JSONObject(entityResponse); - //check requestId - if (! jsonResponse.getString("id").equalsIgnoreCase(requestId)) { - throw new RuntimeException("Invalid response id:" + requestId ); - } + //check requestId + if (!jsonResponse.getString("id").equalsIgnoreCase(requestId)) { + throw new RuntimeException("Invalid response id:" + requestId); + } - msg.setBody(jsonResponse.get("result")); + msg.setBody(jsonResponse.get("result")); } else { - msg.setBody(entityResponse); + msg.setBody(entityResponse); } - + } catch (Exception e) { //FIXME Exceptions are not handled correctly here // They should be reported to the client JavaScript as proper @@ -125,17 +125,18 @@ public class JSONRPCBindingInvoker implements Invoker { return msg; } - + private static JSONObject getJSONRequest(Message msg) { - - JSONObject jsonRequest = null;; + + JSONObject jsonRequest = null; + ; Object[] args = null; Object id = null; try { // Extract the method jsonRequest = new JSONObject(); jsonRequest.putOpt("method", "Service" + "." + msg.getOperation().getName()); - + // Extract the arguments args = msg.getBody(); JSONArray array = new JSONArray(); @@ -151,5 +152,10 @@ public class JSONRPCBindingInvoker implements Invoker { return jsonRequest; } - + + @Override + public boolean allowsPassByReference() { + return true; + } + } diff --git a/sca-java-2.x/trunk/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JSONRPCClient.java b/sca-java-2.x/trunk/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JSONRPCClient.java new file mode 100644 index 0000000000..f427233e52 --- /dev/null +++ b/sca-java-2.x/trunk/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JSONRPCClient.java @@ -0,0 +1,293 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.binding.jsonrpc.provider; + +import java.io.IOException; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.Iterator; + +import javax.xml.bind.annotation.adapters.XmlAdapter; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters; + +import org.codehaus.jackson.JsonFactory; +import org.codehaus.jackson.JsonParser; +import org.codehaus.jackson.map.AnnotationIntrospector; +import org.codehaus.jackson.map.DeserializationConfig; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.map.deser.CustomDeserializerFactory; +import org.codehaus.jackson.map.deser.StdDeserializerProvider; +import org.codehaus.jackson.map.introspect.JacksonAnnotationIntrospector; +import org.codehaus.jackson.map.ser.CustomSerializerFactory; +import org.codehaus.jackson.map.type.TypeFactory; +import org.codehaus.jackson.xc.JaxbAnnotationIntrospector; +import org.codehaus.jackson.xc.XmlAdapterJsonDeserializer; +import org.codehaus.jackson.xc.XmlAdapterJsonSerializer; +import org.jabsorb.JSONRPCBridge; +import org.jabsorb.JSONRPCResult; +import org.jabsorb.JSONSerializer; +import org.jabsorb.client.ClientError; +import org.jabsorb.client.ErrorResponse; +import org.jabsorb.client.Session; +import org.jabsorb.serializer.FixUp; +import org.jabsorb.serializer.SerializerState; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +public class JSONRPCClient implements InvocationHandler { + // private static Logger log = LoggerFactory.getLogger(JsonrpcClient.class); + + private Session session; + private JSONSerializer serializer; + + /** + * Maintain a unique id for each message + */ + private int id = 0; + + /** + * Allow access to the serializer + * + * @return The serializer for this class + */ + public JSONSerializer getSerializer() { + return serializer; + } + + /** + * Create a client given a session + * + * @param session -- + * transport session to use for this connection + */ + public JSONRPCClient(Session session) { + try { + this.session = session; + serializer = new JSONSerializer(); + serializer.registerDefaultSerializers(); + serializer.setMarshallClassHints(false); + serializer.setMarshallNullAttributes(false); + } catch (Exception e) { + throw new ClientError(e); + } + } + + private synchronized int getId() { + return id++; + } + + /** Manual instantiation of HashMap */ + private static class ProxyMap extends HashMap { + public String getString(Object key) { + return (String)super.get(key); + } + + public Object putString(String key, Object value) { + return super.put(key, value); + } + } + + private ProxyMap proxyMap = new ProxyMap(); + + /** + * Create a proxy for communicating with the remote service. + * + * @param key + * the remote object key + * @param klass + * the class of the interface the remote object should adhere to + * @return created proxy + */ + public Object openProxy(String key, Class klass) { + Object result = java.lang.reflect.Proxy.newProxyInstance(klass.getClassLoader(), new Class[] {klass}, this); + proxyMap.put(result, key); + return result; + } + + /** + * Dispose of the proxy that is no longer needed + * + * @param proxy + */ + public void closeProxy(Object proxy) { + proxyMap.remove(proxy); + } + + /** + * This method is public because of the inheritance from the + * InvokationHandler -- should never be called directly. + */ + public Object invoke(Object proxyObj, Method method, Object[] args) throws Exception { + String methodName = method.getName(); + if (methodName.equals("hashCode")) { + return new Integer(System.identityHashCode(proxyObj)); + } else if (methodName.equals("equals")) { + return (proxyObj == args[0] ? Boolean.TRUE : Boolean.FALSE); + } else if (methodName.equals("toString")) { + return proxyObj.getClass().getName() + '@' + Integer.toHexString(proxyObj.hashCode()); + } + return invoke(proxyMap.getString(proxyObj), + method.getName(), + args, + method.getReturnType(), + method.getGenericReturnType()); + } + + private Object invoke(String objectTag, String methodName, Object[] args, Class returnType, Type genericReturnType) + throws Exception { + final int id = getId(); + JSONObject message = new JSONObject(); + String methodTag = objectTag == null ? "" : objectTag + "."; + methodTag += methodName; + message.put("method", methodTag); + + { + SerializerState state = new SerializerState(); + + if (args != null) { + + JSONArray params = marshal(args); // (JSONArray)serializer.marshall(state, /* parent */ null, args, "params"); + + if ((state.getFixUps() != null) && (state.getFixUps().size() > 0)) { + JSONArray fixups = new JSONArray(); + for (Iterator i = state.getFixUps().iterator(); i.hasNext();) { + FixUp fixup = (FixUp)i.next(); + fixups.put(fixup.toJSONArray()); + } + message.put("fixups", fixups); + } + message.put("params", params); + } else { + message.put("params", new JSONArray()); + } + } + message.put("id", id); + + JSONObject responseMessage = session.sendAndReceive(message); + + if (!responseMessage.has("result")) { + processException(responseMessage); + } + Object rawResult = responseMessage.get("result"); + if (rawResult == null) { + processException(responseMessage); + } + if (returnType.equals(Void.TYPE)) { + return null; + } + + { + JSONArray fixups = responseMessage.optJSONArray("fixups"); + + if (fixups != null) { + for (int i = 0; i < fixups.length(); i++) { + JSONArray assignment = fixups.getJSONArray(i); + JSONArray fixup = assignment.getJSONArray(0); + JSONArray original = assignment.getJSONArray(1); + JSONRPCBridge.applyFixup(rawResult, fixup, original); + } + } + } + if (returnType.isInterface()) { + ObjectMapper mapper = createObjectMapper(returnType); + return mapper.readValue(rawResult.toString(), TypeFactory.type(genericReturnType)); + } + return serializer.unmarshall(new SerializerState(), returnType, rawResult); + } + + private JSONArray marshal(Object[] args) throws Exception { + if(args==null) { + return new JSONArray(); + } + ObjectMapper mapper = createObjectMapper(null); + String json = mapper.writeValueAsString(args); + return new JSONArray(json); + } + + public static JsonParser createJsonParser(String content) { + JsonFactory jsonFactory = new JsonFactory(); + try { + return jsonFactory.createJsonParser(content); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + } + + public static ObjectMapper createObjectMapper(Class cls) { + ObjectMapper mapper = new ObjectMapper(); + if (cls != null) { + // Workaround for http://jira.codehaus.org/browse/JACKSON-413 + Package pkg = cls.getPackage(); + if (pkg != null) { + XmlJavaTypeAdapters adapters = pkg.getAnnotation(XmlJavaTypeAdapters.class); + if (adapters != null) { + CustomSerializerFactory serializerFactory = new CustomSerializerFactory(); + CustomDeserializerFactory deserializerFactory = new CustomDeserializerFactory(); + for (XmlJavaTypeAdapter a : adapters.value()) { + XmlAdapter xmlAdapter = null; + try { + xmlAdapter = a.value().newInstance(); + } catch (Throwable e) { + // Ignore + } + if (xmlAdapter != null) { + XmlAdapterJsonDeserializer deserializer = new XmlAdapterJsonDeserializer(xmlAdapter); + XmlAdapterJsonSerializer serializer = new XmlAdapterJsonSerializer(xmlAdapter); + deserializerFactory.addSpecificMapping(a.type(), deserializer); + serializerFactory.addGenericMapping(a.type(), serializer); + StdDeserializerProvider deserializerProvider = + new StdDeserializerProvider(deserializerFactory); + mapper.setSerializerFactory(serializerFactory); + mapper.setDeserializerProvider(deserializerProvider); + } + } + } + } + } + AnnotationIntrospector primary = new JaxbAnnotationIntrospector(); + AnnotationIntrospector secondary = new JacksonAnnotationIntrospector(); + AnnotationIntrospector pair = new AnnotationIntrospector.Pair(primary, secondary); + mapper.getDeserializationConfig().setAnnotationIntrospector(pair); + // [rfeng] To avoid complaints about javaClass + mapper.getDeserializationConfig().set(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, Boolean.FALSE); + mapper.getSerializationConfig().setAnnotationIntrospector(pair); + return mapper; + } + + /** + * Generate and throw exception based on the data in the 'responseMessage' + */ + protected void processException(JSONObject responseMessage) throws JSONException { + JSONObject error = (JSONObject)responseMessage.get("error"); + if (error != null) { + Integer code = new Integer(error.has("code") ? error.getInt("code") : 0); + String trace = error.has("trace") ? error.getString("trace") : null; + String msg = error.has("msg") ? error.getString("msg") : null; + throw new ErrorResponse(code, msg, trace); + } else + throw new ErrorResponse(new Integer(JSONRPCResult.CODE_ERR_PARSE), + "Unknown response:" + responseMessage.toString(2), null); + } + +} diff --git a/sca-java-2.x/trunk/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JSONRPCClientInvoker.java b/sca-java-2.x/trunk/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JSONRPCClientInvoker.java index 2b0859c416..3b2d2b707d 100644 --- a/sca-java-2.x/trunk/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JSONRPCClientInvoker.java +++ b/sca-java-2.x/trunk/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JSONRPCClientInvoker.java @@ -26,9 +26,9 @@ import org.apache.tuscany.sca.assembly.EndpointReference; import org.apache.tuscany.sca.binding.jsonrpc.JSONRPCBinding; import org.apache.tuscany.sca.interfacedef.Operation; import org.apache.tuscany.sca.interfacedef.java.JavaOperation; +import org.apache.tuscany.sca.invocation.DataExchangeSemantics; import org.apache.tuscany.sca.invocation.Invoker; import org.apache.tuscany.sca.invocation.Message; -import org.jabsorb.client.Client; import org.jabsorb.client.Session; import org.jabsorb.client.TransportRegistry; @@ -37,7 +37,7 @@ import org.jabsorb.client.TransportRegistry; * * @version $Rev$ $Date$ */ -public class JSONRPCClientInvoker implements Invoker { +public class JSONRPCClientInvoker implements Invoker, DataExchangeSemantics { private EndpointReference endpointReference; private Operation operation; private Method method; @@ -52,7 +52,7 @@ public class JSONRPCClientInvoker implements Invoker { public Message invoke(Message msg) { Session session = TransportRegistry.i().createSession(uri); - Client client = new Client(session); + JSONRPCClient client = new JSONRPCClient(session); Object proxy = client.openProxy("", method.getDeclaringClass()); try { @@ -66,5 +66,10 @@ public class JSONRPCClientInvoker implements Invoker { } return msg; } - + + @Override + public boolean allowsPassByReference() { + return true; + } + } diff --git a/sca-java-2.x/trunk/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JSONRPCReferenceBindingProvider.java b/sca-java-2.x/trunk/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JSONRPCReferenceBindingProvider.java index adc19202b3..3eaf6ceb7a 100644 --- a/sca-java-2.x/trunk/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JSONRPCReferenceBindingProvider.java +++ b/sca-java-2.x/trunk/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JSONRPCReferenceBindingProvider.java @@ -56,7 +56,7 @@ public class JSONRPCReferenceBindingProvider implements ReferenceBindingProvider public JSONRPCReferenceBindingProvider(EndpointReference endpointReference) { this.endpointReference = endpointReference; - this.reference = (RuntimeComponentReference) endpointReference.getReference(); + this.reference = (RuntimeComponentReference)endpointReference.getReference(); //clone the service contract to avoid databinding issues /* @@ -70,6 +70,10 @@ public class JSONRPCReferenceBindingProvider implements ReferenceBindingProvider */ // Create an HTTP client + httpClient = createHttpClient(); + } + + public HttpClient createHttpClient() { HttpParams defaultParameters = new BasicHttpParams(); //defaultParameters.setIntParameter(HttpConnectionManagerParams.MAX_TOTAL_CONNECTIONS, 10); HttpProtocolParams.setContentCharset(defaultParameters, HTTP.UTF_8); @@ -79,9 +83,10 @@ public class JSONRPCReferenceBindingProvider implements ReferenceBindingProvider SchemeRegistry supportedSchemes = new SchemeRegistry(); supportedSchemes.register(new Scheme(HttpHost.DEFAULT_SCHEME_NAME, PlainSocketFactory.getSocketFactory(), 80)); - ClientConnectionManager connectionManager = new ThreadSafeClientConnManager(defaultParameters, supportedSchemes); + ClientConnectionManager connectionManager = + new ThreadSafeClientConnManager(defaultParameters, supportedSchemes); - httpClient = new DefaultHttpClient(connectionManager, defaultParameters); + return new DefaultHttpClient(connectionManager, defaultParameters); } public InterfaceContract getBindingInterfaceContract() { @@ -90,10 +95,10 @@ public class JSONRPCReferenceBindingProvider implements ReferenceBindingProvider } public Invoker createInvoker(Operation operation) { - final Interface intf = reference.getInterfaceContract().getInterface(); - if (intf.isDynamic()) { - return new JSONRPCBindingInvoker(endpointReference, operation, httpClient); - } + final Interface intf = reference.getInterfaceContract().getInterface(); + if (intf.isDynamic()) { + return new JSONRPCBindingInvoker(endpointReference, operation, httpClient); + } return new JSONRPCClientInvoker(endpointReference, operation, httpClient); } diff --git a/sca-java-2.x/trunk/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextHelper.java b/sca-java-2.x/trunk/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextHelper.java index 13eceb0d9a..9fa9038006 100644 --- a/sca-java-2.x/trunk/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextHelper.java +++ b/sca-java-2.x/trunk/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextHelper.java @@ -18,6 +18,7 @@ */ package org.apache.tuscany.sca.databinding.jaxb; +import java.lang.reflect.Array; import java.lang.reflect.GenericArrayType; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; @@ -363,6 +364,31 @@ public final class JAXBContextHelper { return cls; } } + + private static Class erase(Type type) { + if (type instanceof Class) { + return (Class)type; + } + if (type instanceof ParameterizedType) { + ParameterizedType pt = (ParameterizedType)type; + return (Class)pt.getRawType(); + } + if (type instanceof TypeVariable) { + TypeVariable tv = (TypeVariable)type; + Type[] bounds = tv.getBounds(); + return (0 < bounds.length) ? erase(bounds[0]) : Object.class; + } + if (type instanceof WildcardType) { + WildcardType wt = (WildcardType)type; + Type[] bounds = wt.getUpperBounds(); + return (0 < bounds.length) ? erase(bounds[0]) : Object.class; + } + if (type instanceof GenericArrayType) { + GenericArrayType gat = (GenericArrayType)type; + return Array.newInstance(erase(gat.getGenericComponentType()), 0).getClass(); + } + throw new IllegalArgumentException("Unknown Type kind: " + type.getClass()); + } public static Class getValueType(XmlJavaTypeAdapter adapter) { if (adapter != null) { @@ -371,9 +397,9 @@ public final class JAXBContextHelper { Type superClass = adapterClass.getGenericSuperclass(); while (superClass instanceof ParameterizedType && XmlAdapter.class != ((ParameterizedType)superClass) .getRawType()) { - superClass = ((Class)((ParameterizedType)superClass).getRawType()).getGenericSuperclass(); + superClass = erase(superClass).getGenericSuperclass(); } - return (Class)((ParameterizedType)superClass).getActualTypeArguments()[0]; + return erase(((ParameterizedType)superClass).getActualTypeArguments()[0]); } } return null; diff --git a/sca-java-2.x/trunk/modules/databinding-json/META-INF/MANIFEST.MF b/sca-java-2.x/trunk/modules/databinding-json/META-INF/MANIFEST.MF index 42674a55f8..2882a31966 100644 --- a/sca-java-2.x/trunk/modules/databinding-json/META-INF/MANIFEST.MF +++ b/sca-java-2.x/trunk/modules/databinding-json/META-INF/MANIFEST.MF @@ -21,7 +21,9 @@ Import-Package: javax.xml.namespace, org.apache.tuscany.sca.interfacedef.util;version="2.0.0", org.codehaus.jackson, org.codehaus.jackson.map, + org.codehaus.jackson.map.deser, org.codehaus.jackson.map.introspect, + org.codehaus.jackson.map.ser, org.codehaus.jackson.map.type, org.codehaus.jackson.type, org.codehaus.jackson.xc;resolution:=optional, diff --git a/sca-java-2.x/trunk/modules/databinding-json/src/main/java/org/apache/tuscany/sca/databinding/json/jackson/JSON2Object.java b/sca-java-2.x/trunk/modules/databinding-json/src/main/java/org/apache/tuscany/sca/databinding/json/jackson/JSON2Object.java index ca28ec5833..c7ae9d636d 100644 --- a/sca-java-2.x/trunk/modules/databinding-json/src/main/java/org/apache/tuscany/sca/databinding/json/jackson/JSON2Object.java +++ b/sca-java-2.x/trunk/modules/databinding-json/src/main/java/org/apache/tuscany/sca/databinding/json/jackson/JSON2Object.java @@ -38,7 +38,6 @@ public class JSON2Object implements PullTransformer { public JSON2Object() { super(); - mapper = JacksonHelper.createObjectMapper(); } public Object transform(Object source, TransformationContext context) { @@ -47,6 +46,8 @@ public class JSON2Object implements PullTransformer { } try { + Class cls = context.getTargetDataType().getPhysical(); + ObjectMapper mapper = JacksonHelper.createObjectMapper(cls); JavaType javaType = TypeFactory.type(context.getTargetDataType().getGenericType()); if (source instanceof String) { String sourceString = (String) source; diff --git a/sca-java-2.x/trunk/modules/databinding-json/src/main/java/org/apache/tuscany/sca/databinding/json/jackson/JacksonHelper.java b/sca-java-2.x/trunk/modules/databinding-json/src/main/java/org/apache/tuscany/sca/databinding/json/jackson/JacksonHelper.java index ae3bb8fd48..00ddc2601d 100644 --- a/sca-java-2.x/trunk/modules/databinding-json/src/main/java/org/apache/tuscany/sca/databinding/json/jackson/JacksonHelper.java +++ b/sca-java-2.x/trunk/modules/databinding-json/src/main/java/org/apache/tuscany/sca/databinding/json/jackson/JacksonHelper.java @@ -25,6 +25,10 @@ import java.io.OutputStream; import java.io.Reader; import java.io.StringWriter; +import javax.xml.bind.annotation.adapters.XmlAdapter; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters; + import org.codehaus.jackson.JsonEncoding; import org.codehaus.jackson.JsonFactory; import org.codehaus.jackson.JsonGenerator; @@ -32,16 +36,63 @@ import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.JsonParser; import org.codehaus.jackson.map.AnnotationIntrospector; import org.codehaus.jackson.map.DeserializationConfig; +import org.codehaus.jackson.map.MappingJsonFactory; import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.map.deser.CustomDeserializerFactory; +import org.codehaus.jackson.map.deser.StdDeserializerProvider; import org.codehaus.jackson.map.introspect.JacksonAnnotationIntrospector; +import org.codehaus.jackson.map.ser.CustomSerializerFactory; import org.codehaus.jackson.xc.JaxbAnnotationIntrospector; +import org.codehaus.jackson.xc.XmlAdapterJsonDeserializer; +import org.codehaus.jackson.xc.XmlAdapterJsonSerializer; /** * */ public class JacksonHelper { - public static ObjectMapper createObjectMapper() { - ObjectMapper mapper = new ObjectMapper(); + private final static ObjectMapper MAPPER = createMapper(); + private final static JsonFactory FACTORY = new MappingJsonFactory(createMapper()); + + public static ObjectMapper createMapper() { + return createObjectMapper(null); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + public static ObjectMapper createObjectMapper(Class cls) { + ObjectMapper mapper = null; + if (cls != null) { + // Workaround for http://jira.codehaus.org/browse/JACKSON-413 + Package pkg = cls.getPackage(); + if (pkg != null) { + XmlJavaTypeAdapters adapters = pkg.getAnnotation(XmlJavaTypeAdapters.class); + if (adapters != null) { + CustomSerializerFactory serializerFactory = new CustomSerializerFactory(); + CustomDeserializerFactory deserializerFactory = new CustomDeserializerFactory(); + for (XmlJavaTypeAdapter a : adapters.value()) { + XmlAdapter xmlAdapter = null; + try { + xmlAdapter = a.value().newInstance(); + } catch (Throwable e) { + // Ignore + } + if (xmlAdapter != null) { + XmlAdapterJsonDeserializer deserializer = new XmlAdapterJsonDeserializer(xmlAdapter); + XmlAdapterJsonSerializer serializer = new XmlAdapterJsonSerializer(xmlAdapter); + deserializerFactory.addSpecificMapping(a.type(), deserializer); + serializerFactory.addGenericMapping(a.type(), serializer); + StdDeserializerProvider deserializerProvider = + new StdDeserializerProvider(deserializerFactory); + mapper = new ObjectMapper(); + mapper.setSerializerFactory(serializerFactory); + mapper.setDeserializerProvider(deserializerProvider); + } + } + } + } + } + if (mapper == null) { + mapper = new ObjectMapper(); + } AnnotationIntrospector primary = new JaxbAnnotationIntrospector(); AnnotationIntrospector secondary = new JacksonAnnotationIntrospector(); AnnotationIntrospector pair = new AnnotationIntrospector.Pair(primary, secondary); @@ -52,13 +103,13 @@ public class JacksonHelper { return mapper; } + public static JsonFactory getJsonFactory() { + return FACTORY; + } + public static String toString(JsonNode node) { try { - JsonFactory jsonFactory = new JsonFactory(); - StringWriter sw = new StringWriter(); - JsonGenerator generator = jsonFactory.createJsonGenerator(sw); - generator.writeTree(node); - return sw.toString(); + return MAPPER.writeValueAsString(node); } catch (IOException e) { throw new IllegalArgumentException(e); } @@ -66,7 +117,7 @@ public class JacksonHelper { public static String toString(JsonParser parser) { try { - JsonFactory jsonFactory = new JsonFactory(); + JsonFactory jsonFactory = getJsonFactory(); StringWriter sw = new StringWriter(); JsonGenerator generator = jsonFactory.createJsonGenerator(sw); JsonNode node = parser.readValueAs(JsonNode.class); @@ -78,7 +129,7 @@ public class JacksonHelper { } public static JsonParser createJsonParser(String content) { - JsonFactory jsonFactory = new JsonFactory(); + JsonFactory jsonFactory = getJsonFactory(); try { return jsonFactory.createJsonParser(content); } catch (IOException e) { @@ -87,26 +138,26 @@ public class JacksonHelper { } public static JsonParser createJsonParser(InputStream content) { - JsonFactory jsonFactory = new JsonFactory(); + JsonFactory jsonFactory = getJsonFactory(); try { return jsonFactory.createJsonParser(content); } catch (IOException e) { throw new IllegalArgumentException(e); } } - + public static JsonParser createJsonParser(Reader content) { - JsonFactory jsonFactory = new JsonFactory(); + JsonFactory jsonFactory = getJsonFactory(); try { return jsonFactory.createJsonParser(content); } catch (IOException e) { throw new IllegalArgumentException(e); } - } + } public static void write(JsonNode node, OutputStream out) { try { - JsonFactory jsonFactory = new JsonFactory(); + JsonFactory jsonFactory = getJsonFactory(); JsonGenerator generator = jsonFactory.createJsonGenerator(out, JsonEncoding.UTF8); generator.writeTree(node); } catch (IOException e) { @@ -116,7 +167,7 @@ public class JacksonHelper { public static void write(JsonParser parser, OutputStream out) { try { - JsonFactory jsonFactory = new JsonFactory(); + JsonFactory jsonFactory = getJsonFactory(); JsonGenerator generator = jsonFactory.createJsonGenerator(out, JsonEncoding.UTF8); JsonNode node = parser.readValueAs(JsonNode.class); generator.writeTree(node); @@ -124,5 +175,5 @@ public class JacksonHelper { throw new IllegalArgumentException(e); } } - + } diff --git a/sca-java-2.x/trunk/modules/databinding-json/src/main/java/org/apache/tuscany/sca/databinding/json/jackson/Object2JSON.java b/sca-java-2.x/trunk/modules/databinding-json/src/main/java/org/apache/tuscany/sca/databinding/json/jackson/Object2JSON.java index d543d0554a..38b826b202 100644 --- a/sca-java-2.x/trunk/modules/databinding-json/src/main/java/org/apache/tuscany/sca/databinding/json/jackson/Object2JSON.java +++ b/sca-java-2.x/trunk/modules/databinding-json/src/main/java/org/apache/tuscany/sca/databinding/json/jackson/Object2JSON.java @@ -35,11 +35,9 @@ import org.codehaus.jackson.map.ObjectMapper; * @version $Rev$ $Date$ */ public class Object2JSON implements PullTransformer { - private ObjectMapper mapper; public Object2JSON() { super(); - mapper = JacksonHelper.createObjectMapper(); } public Object transform(Object source, TransformationContext context) { @@ -58,12 +56,11 @@ public class Object2JSON implements PullTransformer { if (targetType != null && targetType.isPrimitive()) { return source; } + ObjectMapper mapper = JacksonHelper.createObjectMapper(targetType); String value = mapper.writeValueAsString(source); - if (targetType == String.class || - targetType == Object.class || - targetType.isPrimitive()) { + if (targetType == String.class || targetType == Object.class || targetType.isPrimitive()) { return value; - } else if (targetType == BigDecimal.class){ + } else if (targetType == BigDecimal.class) { return value.toString(); } else if (JsonNode.class.isAssignableFrom(targetType)) { return JacksonHelper.createJsonParser(value).readValueAsTree(); -- cgit v1.2.3