My question is how to pass object between SI endpoints?
Almost every example I found is using XML settings, I am using Annotation and don't know how to solve this exception
Caused by: java.lang.IllegalArgumentException: Could not resolve 'json__TypeId__' in 'javaTypes'.
at org.springframework.integration.support.json.AbstractJacksonJsonObjectMapper.createJavaType(AbstractJacksonJsonObjectMapper.java:68)
at org.springframework.integration.support.json.Jackson2JsonObjectMapper.extractJavaType(Jackson2JsonObjectMapper.java:116)
at org.springframework.integration.support.json.Jackson2JsonObjectMapper.extractJavaType(Jackson2JsonObjectMapper.java:52)
at org.springframework.integration.support.json.AbstractJacksonJsonObjectMapper.fromJson(AbstractJacksonJsonObjectMapper.java:61)
at org.springframework.integration.json.JsonToObjectTransformer.doTransform(JsonToObjectTransformer.java:87)
at org.springframework.integration.transformer.AbstractTransformer.transform(AbstractTransformer.java:33)
... 18 more
People suggest using xml to fix this, for example
<bean class="org.springframework.amqp.support.converter.DefaultClassMapper">
<property name="defaultType" value="foo.MyObject" />
</bean>
But I am using annotation to create transformer to process messages receive from channel, like this
#Bean
#Transformer(inputChannel="fromTcp", outputChannel="toHandler")
JsonToObjectTransformer jsonToObjectTransformer() {
ObjectMapper mapper = new ObjectMapper();
JsonObjectMapper<JsonNode, JsonParser> jm = new Jackson2JsonObjectMapper(mapper);
return new JsonToObjectTransformer(jm);
}
Actually I have no clue how to pass object between SI endpoints. I could only pass String and SI use default serialize to handle String to byte[], and byte[] to String.
The converter needs to know what type to convert to; the error you are getting is because you haven't provided a type so it falls back to looking for a header containing type information.
The equivalent of the xml is:
#Bean
#Transformer(inputChannel="fromTcp", outputChannel="toHandler")
JsonToObjectTransformer jsonToObjectTransformer() {
return new JsonToObjectTransformer(MyObject.class);
}
Related
I'm using Flink to process some JSON-format data coming from some Data Source.
For now, my process is quite simple: extract each element from the JSON-format data and print them into log file.
Here is my piece of code:
// create proper deserializer to deserializer the JSON-format data into ObjectNode
PravegaDeserializationSchema<ObjectNode> adapter = new PravegaDeserializationSchema<>(ObjectNode.class, new JavaSerializer<>());
// create connector to receive data from Pravega
FlinkPravegaReader<ObjectNode> source = FlinkPravegaReader.<ObjectNode>builder()
.withPravegaConfig(pravegaConfig)
.forStream(stream)
.withDeserializationSchema(adapter)
.build();
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
DataStream<ObjectNode> dataStream = env.addSource(source).name("Pravega Stream");
dataStream.???.print();
Saying that the data coming from Pravega is like this: {"name":"titi", "age":18}
As I said, for now I simply need to extract name and age and print them.
So how could I do this?
As my understanding, I need to make some customized codes at ???. I might need to create a custom POJO class which contains ObjectNode. But I don't know how. I've read the official doc of Flink and also tried to google about how to create a custom POJO for Flink but I can't still figure out clearly.
Could you please show me an example?
Why don't You simply use something more meaningful instead of JavaSerializer? Perhaps something from here.
You could then create a POJO with the fields you want to use and simply deserialize JSON data to Your POJO instead of ObjectNode
Also, if there is some specific reason that You need to have ObjectNode on deserialization then You can simply do something like :
//I assume You have created the class named MyPojo
dataStream.map(new MapFunction<ObjectNode, MyPojo>() {
ObjectMapper mapper = new ObjectMapper();
#Override
public MyPojo map(final ObjectNode value) throws Exception {
mapper.readValue(value.asText(), MyPojo.class)
}
})
I'm really stuck with cast Rabbit response to POJO. How to do it properly? On sprin.io just no practical example.
So I'm trying to do it with this
#Bean
public DefaultClassMapper typeMapper() {
DefaultClassMapper typeMapper = new DefaultClassMapper();
Map<String, Class> idClassMapping = new HashMap<String, Class>();
idClassMapping.put("range", Loan.class);
typeMapper.setIdClassMapping(idClassMapping);
//typeMapper.setDefaultType(Loan.class);
return typeMapper;
}
#Bean
public MessageConverter messageConverter(DefaultClassMapper defaultClassMapper){
JsonMessageConverter jsonMessageConverter = new JsonMessageConverter();
jsonMessageConverter.setClassMapper(defaultClassMapper);
return jsonMessageConverter;
}
"range" actually fake value from example. Also this really doesn't work type problemn on .setIdClassMapping() . Also I can't use default mapper because serve send header without type hinting field. And I have no control on this remote server. Data format always JSON.
Caused by: org.springframework.amqp.support.converter.MessageConversionException: failed to convert Message content. Could not resolve __TypeId__ in header
Any suggestions working example for marshalling/demarshalling Java objects. I have completely different class for send back value from my code. I'm using java 8.
Just write your own ClassMapper - don't use the default one if your decision criteria to choose the class type is not compatible with its internals.
Or, you can subclass the DefaultClassMapper and override getClassIdFieldName() to tell it which message property to use.
I have a jersey webservice running 1.17 and supports returning responses via both XML and JSON via the #Produces annotation. I am assuming it uses JAXB by default when returning JSON responses but I have no way to confirm it. As of now, my existing clients also use the same JAXB serializer/deserializer. I want to create a new client that uses Jackson without impacting the existing clients.
The JAXB JSON response is incompatible for Jackson for Maps. the JSON for a map using JAXB is of the form
"mapName":{"entry":[{"key":"key1","value":"value1"},{"key":"key2","value":"value2"}]}
and Jackson fails to parse this. Is there any way to make jackson parse this JSON?
Another Attempt: Switching Jersey to use Jackson
This isn't the preferred option but I tried setting "com.sun.jersey.api.json.POJOMappingFeature" to true to allow it to use Jackson for JSON Serialization/Deserialization however the service ends up returning 500s on response without logging any exceptions. the log4j logger level is set to TRACE. I enabled the ContainerRepsonseFilter to confirm 500s in the response and to my surprise, it logs the successful 2xx response. My guess is the problem occurs somewhere further down the stack but I don't know where.
I ended up with using MOXy which is able to parse the above json format.
#Provider
public class JsonMoxyConfigurationContextResolver implements ContextResolver {
private final MoxyJsonConfig config;
public JsonMoxyConfigurationContextResolver() {
final Map<String, String> namespacePrefixMapper = new HashMap<String, String>();
namespacePrefixMapper.put("http://www.w3.org/2001/XMLSchema-instance", "xsi");
config = new MoxyJsonConfig()
.setNamespacePrefixMapper(namespacePrefixMapper)
.setNamespaceSeparator(':');
}
#Override
public MoxyJsonConfig getContext(Class<?> objectType) {
return config;
}
}
and enabled it Jersey 2.x client using
cc.register(JsonMoxyConfigurationContextResolver.class);
I have a JAX-RS WebService with the following method:
#Path("/myrest")
public class MyRestResource {
...
#GET
#Path("/getInteger")
#Produces(APPLICATION_JSON)
public Integer getInteger() {
return 42;
}
When accessed using this snipped:
#Test
public void testGetPrimitiveWrapers() throws IOException {
// this works:
assertEquals(new Integer(42), new ObjectMapper().readValue("42", Integer.class));
// that fails:
assertEquals(new Integer(42), resource().path("/myrest/getInteger").get(Integer.class));
}
I get the following exception:
com.sun.jersey.api.client.ClientResponse getEntity
SEVERE: A message body reader for Java class java.lang.Integer, and Java type class java.lang.Integer, and MIME media type application/json was not found
com.sun.jersey.api.client.ClientResponse getEntity
SEVERE: The registered message body readers compatible with the MIME media type are: application/json
...
The problem is just with returning single primitive values (int/boolean) or their wrapper classes. Returning other POJO classes is not the problemen so I guess all the answers regarding JSONConfiguration.FEATURE_POJO_MAPPING and JAXB annotations do not apply here.
Or which annotation should I use to describe the return type if I don't have access to its
class source?
Using ngrep I can verify that just the String "42" is returned by the webservice. Thats a valid JSON "value" but not a valid JSON "text" according to the spec. So is my problem on the client or the server side?
I tried activating JSONConfiguration natural/badgerfish according to http://tugdualgrall.blogspot.de/2011/09/jax-rs-jersey-and-single-element-arrays.html but with no success (ngrep still shows just "42"). Would that be the right path?
Any ideas are appreciated!
This is a recognized bug in Jackson, which has been touted (incorrectly in my opinion) as a feature. Why do I consider it a bug? Because while serialization works, deserialization definitely does not.
In any case, valid JSON cannot be generated from your current return type, so I would recommend creating a wrapper class:
class Result<T> {
private T data;
// constructors, getters, setters
}
#GET
#Path("/getInteger")
#Produces(APPLICATION_JSON)
public Result<Integer> getInteger() {
return new Result<Integer)(42);
}
Alternatively, you can elect to wrap root values, which will automatically encapsulate your data in a top level JSON object, keyed by the objects simple type name - but note that if this option is used that all generated JSON will be wrapped (not just for primitives):
final ObjectMapper mapper = new ObjectMapper()
.configure(SerializationFeature.WRAP_ROOT_VALUE, true)
.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
final String serializedJson = mapper.writeValueAsString(42);
final Integer deserializedVal = mapper.readValue(serializedJson,
Integer.class);
System.out.println(serializedJson);
System.out.println("Deserialized Value: " + deserializedVal);
Output:
{"Integer":42}
Deserialized Value: 42
See this answer for details on how to retrieve and configure your ObjectMapper instance in a JAX-RS environment.
I am trying to host a WCF service that responds to incoming requests by providing a json output stream. I have the following type
[DataContract]
[KnownType(typeof(List<HubCommon>))]
[KnownType(typeof(Music))]
[KnownType(typeof(AppsAndPlugins))]
[KnownType(typeof(Notifications))]
[KnownType(typeof(Scenes))]
[KnownType(typeof(Skins))]
[KnownType(typeof(Ringtones))]
[KnownType(typeof(Alarms))]
[KnownType(typeof(Widgets))]
[KnownType(typeof(Wallpapers))]
[KnownType(typeof(Soundsets))]
public class HubCommon{}
In my *.svc.cs file I do the following
List<HubCommon> hubContent = _ldapFacade.GetResults(query);
MemoryStream stream = new MemoryStream();
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(HubCommon));
serializer.WriteObject(stream,hubContent);
So essentially I am trying to serialize a List to Json but I get the following error on the "WriteObject" execution:-
The server encountered an error processing the request. The exception message is 'Type 'System.Collections.Generic.List`1[[HubContentCore.Domain.HubCommon, HubContentCore, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' with data contract name 'ArrayOfHubCommon:http://schemas.datacontract.org/2004/07/HubContentCore.Domain' is not expected. Add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.'
What am I missing here ?
Thanks in advance.
The type of your DataContractJsonSerializer is HubCommon but you are writing an object of type List<HubCommon> and HubCommon is not added to the KnownTypAttribute