Skip to content

Commit 7ec9292

Browse files
author
David Syer
committed
SPR-7404: Added JsonMessageConverter, borrowing from Spring AMQP
1 parent 3beef9a commit 7ec9292

File tree

6 files changed

+747
-0
lines changed

6 files changed

+747
-0
lines changed

org.springframework.jms/ivy.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
<conf name="commons-pool" extends="runtime" description="JARs needed to run with Commons Pool"/>
1414
<conf name="jca" extends="runtime" description="JARs needed to develop JCA beans"/>
1515
<conf name="oxm" extends="runtime" description="JARs needed to use the MarshallingMessageConverter"/>
16+
<conf name="jackson" extends="runtime" description="JARs needed to use the Jackson JSON View"/>
1617
</configurations>
1718

1819
<publications>
@@ -35,6 +36,8 @@
3536
conf="optional, commons-pool->compile"/>
3637
<dependency org="org.easymock" name="com.springsource.org.easymock" rev="2.5.1" conf="test->compile"/>
3738
<dependency org="org.junit" name="com.springsource.org.junit" rev="${junit.version}" conf="test->compile"/>
39+
<dependency org="org.codehaus.jackson" name="com.springsource.org.codehaus.jackson.mapper" rev="1.4.2"
40+
conf="optional, jackson->compile"/>
3841
<dependency org="org.springframework" name="org.springframework.aop" rev="latest.integration"
3942
conf="compile->compile"/>
4043
<dependency org="org.springframework" name="org.springframework.beans" rev="latest.integration"

org.springframework.jms/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,12 @@
9090
<version>${project.version}</version>
9191
<scope>compile</scope>
9292
</dependency>
93+
<dependency>
94+
<groupId>org.codehaus.jackson</groupId>
95+
<artifactId>jackson-mapper-asl</artifactId>
96+
<version>1.4.2</version>
97+
<optional>true</optional>
98+
</dependency>
9399
</dependencies>
94100
<build>
95101
<pluginManagement>
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/*
2+
* Copyright 2002-2010 the original author or authors. Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License. You may obtain a copy of the License at
4+
* http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software
5+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
6+
* either express or implied. See the License for the specific language governing permissions and limitations under the
7+
* License.
8+
*/
9+
package org.springframework.jms.support.converter;
10+
11+
import static org.codehaus.jackson.map.type.TypeFactory.collectionType;
12+
import static org.codehaus.jackson.map.type.TypeFactory.mapType;
13+
import static org.codehaus.jackson.map.type.TypeFactory.type;
14+
15+
import java.util.Collection;
16+
import java.util.HashMap;
17+
import java.util.Map;
18+
import java.util.Map.Entry;
19+
20+
import javax.jms.JMSException;
21+
import javax.jms.Message;
22+
23+
import org.codehaus.jackson.type.JavaType;
24+
import org.springframework.beans.factory.InitializingBean;
25+
import org.springframework.util.ClassUtils;
26+
27+
/**
28+
* Default implementation of {@link JavaTypeMapper} using hard coded message
29+
* properties to store and retrieve the content type information.
30+
*
31+
* @author Mark Pollack
32+
* @author Sam Nelson
33+
* @author Dave Syer
34+
**/
35+
public class DefaultJavaTypeMapper implements JavaTypeMapper, InitializingBean {
36+
37+
public static final String CLASSID_PROPERTY_NAME = "__TypeId__";
38+
public static final String CONTENT_CLASSID_PROPERTY_NAME = "__ContentTypeId__";
39+
public static final String KEY_CLASSID_PROPERTY_NAME = "__KeyTypeId__";
40+
41+
private Map<String, Class<?>> idClassMapping = new HashMap<String, Class<?>>();
42+
private Map<Class<?>, String> classIdMapping = new HashMap<Class<?>, String>();
43+
44+
@SuppressWarnings({ "unchecked", "rawtypes" })
45+
public JavaType toJavaType(Message message) throws JMSException {
46+
JavaType classType = getClassIdType(retrieveHeader(message,
47+
CLASSID_PROPERTY_NAME));
48+
if (!classType.isContainerType()) {
49+
return classType;
50+
}
51+
52+
JavaType contentClassType = getClassIdType(retrieveHeader(message,
53+
CONTENT_CLASSID_PROPERTY_NAME));
54+
if (classType.getKeyType() == null) {
55+
return collectionType(
56+
(Class<? extends Collection>) classType.getRawClass(),
57+
contentClassType);
58+
}
59+
60+
JavaType keyClassType = getClassIdType(retrieveHeader(message,
61+
KEY_CLASSID_PROPERTY_NAME));
62+
JavaType mapType = mapType(
63+
(Class<? extends Map>) classType.getRawClass(), keyClassType,
64+
contentClassType);
65+
return mapType;
66+
67+
}
68+
69+
private JavaType getClassIdType(String classId) {
70+
if (this.idClassMapping.containsKey(classId)) {
71+
return type(idClassMapping.get(classId));
72+
}
73+
74+
try {
75+
return type(ClassUtils
76+
.forName(classId, getClass().getClassLoader()));
77+
} catch (ClassNotFoundException e) {
78+
throw new MessageConversionException(
79+
"failed to resolve class name. Class not found [" + classId
80+
+ "]", e);
81+
} catch (LinkageError e) {
82+
throw new MessageConversionException(
83+
"failed to resolve class name. Linkage error [" + classId
84+
+ "]", e);
85+
}
86+
}
87+
88+
private String retrieveHeader(Message message, String headerName)
89+
throws JMSException {
90+
String classId = message.getStringProperty(headerName);
91+
if (classId == null) {
92+
throw new MessageConversionException(
93+
"failed to convert Message content. Could not resolve "
94+
+ headerName + " in header");
95+
}
96+
return classId;
97+
}
98+
99+
public void setIdClassMapping(Map<String, Class<?>> idClassMapping) {
100+
this.idClassMapping = idClassMapping;
101+
}
102+
103+
public void fromJavaType(JavaType javaType, Message message)
104+
throws JMSException {
105+
addHeader(message, CLASSID_PROPERTY_NAME,
106+
(Class<?>) javaType.getRawClass());
107+
108+
if (javaType.isContainerType()) {
109+
addHeader(message, CONTENT_CLASSID_PROPERTY_NAME, javaType
110+
.getContentType().getRawClass());
111+
}
112+
113+
if (javaType.getKeyType() != null) {
114+
addHeader(message, KEY_CLASSID_PROPERTY_NAME, javaType.getKeyType()
115+
.getRawClass());
116+
}
117+
}
118+
119+
public void afterPropertiesSet() throws Exception {
120+
validateIdTypeMapping();
121+
}
122+
123+
private void addHeader(Message message, String headerName, Class<?> clazz)
124+
throws JMSException {
125+
if (classIdMapping.containsKey(clazz)) {
126+
message.setStringProperty(headerName, classIdMapping.get(clazz));
127+
} else {
128+
message.setStringProperty(headerName, clazz.getName());
129+
}
130+
}
131+
132+
private void validateIdTypeMapping() {
133+
Map<String, Class<?>> finalIdClassMapping = new HashMap<String, Class<?>>();
134+
for (Entry<String, Class<?>> entry : idClassMapping.entrySet()) {
135+
String id = entry.getKey();
136+
Class<?> clazz = entry.getValue();
137+
finalIdClassMapping.put(id, clazz);
138+
classIdMapping.put(clazz, id);
139+
}
140+
this.idClassMapping = finalIdClassMapping;
141+
}
142+
143+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright 2002-2010 the original author or authors. Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License. You may obtain a copy of the License at
4+
* http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software
5+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
6+
* either express or implied. See the License for the specific language governing permissions and limitations under the
7+
* License.
8+
*/
9+
10+
package org.springframework.jms.support.converter;
11+
12+
import javax.jms.JMSException;
13+
import javax.jms.Message;
14+
15+
import org.codehaus.jackson.type.JavaType;
16+
17+
/**
18+
* Strategy for setting metadata on messages such that one can create the class that needs to be instantiated when
19+
* receiving a message.
20+
*
21+
* @author Dave Syer
22+
* @author Sam Nelson
23+
*/
24+
public interface JavaTypeMapper {
25+
26+
void fromJavaType(JavaType javaType, Message message) throws JMSException;
27+
28+
JavaType toJavaType(Message message) throws JMSException;
29+
30+
}

0 commit comments

Comments
 (0)