I am trying to convert messages from PubSub to a JSON object which I can use later for filtering and inserting into BigQuery. Currently, I am getting an error converting the message to a JSON object.
Input from PubSubMessage:
[
{
"name": "test-name",
"details": {
"email": "test-email",
"location": "test-location"
}
},
{
"name": "test-name2"
}
]
In the above message, the details field can be nullable.
Pipeline code:
import org.apache.beam.sdk.values.PCollection;
import org.apache.beam.sdk.Pipeline;
import org.apache.beam.sdk.coders.AvroCoder;
import org.apache.beam.sdk.coders.DefaultCoder;
import org.apache.beam.sdk.options.PipelineOptionsFactory;
import org.apache.beam.sdk.transforms.DoFn;
import org.apache.beam.sdk.transforms.ParDo;
import org.apache.beam.sdk.io.gcp.pubsub.PubsubIO;
import org.apache.beam.sdk.io.gcp.pubsub.PubsubOptions;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import javax.annotation.Nullable;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import org.apache.beam.sdk.io.gcp.pubsub.PubsubMessage;
#DefaultCoder(AvroCoder.class)
class Raw {
public String name;
#Nullable
Details details;
}
class Details {
public String email;
public String location;
}
public class DataFlowPipeline {
public static void main(String[] args) {
PubsubOptions options = PipelineOptionsFactory.fromArgs(args)
.withValidation()
.as(PubsubOptions.class);
options.setPubsubRootUrl("http://localhost:8085");
Pipeline pipeline = Pipeline.create(options);
PCollection<List<Raw>> message = pipeline
.apply("ReadPubSubTopic", PubsubIO.readMessagesWithAttributes().fromTopic("projects/test-dataflow/topics/demo-dataflow"))
.apply("DeserializePubSubMessage", ParDo.of(new DoFn<PubsubMessage, List<Raw>>() {
#ProcessElement
public void processElement(ProcessContext c) {
System.out.println("Inside processor..");
PubsubMessage message = c.element();
String payload = new String(message.getPayload(), StandardCharsets.UTF_8);
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
TypeFactory typeFactory = mapper.getTypeFactory();
try {
List<Raw> data = mapper.readValue(payload, typeFactory.constructCollectionType(List.class, Raw.class));
System.out.println("Message = " + data);
c.output(data);
} catch (IOException e) {
e.printStackTrace();
}
}}));
;
pipeline.run().waitUntilFinish();;
}
}
Executing the pipeline returns a Null Pointer Exception in Data Reflection. Based on AvroCoder documentation Nullable annotations allows the null fields.
Error:
Caused by: java.lang.NullPointerException: in com.company.dataflow.Raw in com.company.dataflow.Raw in string null of string in field name of com.company.dataflow.Details in field details of com.company.dataflow.Message
at org.apache.avro.reflect.ReflectDatumWriter.write(ReflectDatumWriter.java:161)
at org.apache.avro.generic.GenericDatumWriter.write(GenericDatumWriter.java:62)
at org.apache.beam.sdk.coders.AvroCoder.encode(AvroCoder.java:312)
at org.apache.beam.sdk.coders.IterableLikeCoder.encode(IterableLikeCoder.java:114)
at org.apache.beam.sdk.coders.IterableLikeCoder.encode(IterableLikeCoder.java:60)
at org.apache.beam.sdk.coders.Coder.encode(Coder.java:136)
at org.apache.beam.sdk.util.CoderUtils.encodeToSafeStream(CoderUtils.java:82)
at org.apache.beam.sdk.util.CoderUtils.encodeToByteArray(CoderUtils.java:66)
at org.apache.beam.sdk.util.CoderUtils.encodeToByteArray(CoderUtils.java:51)
at org.apache.beam.sdk.util.CoderUtils.clone(CoderUtils.java:141)
at org.apache.beam.sdk.util.MutationDetectors$CodedValueMutationDetector.<init>(MutationDetectors.java:115)
at org.apache.beam.sdk.util.MutationDetectors.forValueWithCoder(MutationDetectors.java:46)
at org.apache.beam.runners.direct.ImmutabilityCheckingBundleFactory$ImmutabilityEnforcingBundle.add(ImmutabilityCheckingBundleFactory.java:112)
at org.apache.beam.runners.direct.ParDoEvaluator$BundleOutputManager.output(ParDoEvaluator.java:300)
at org.apache.beam.repackaged.direct_java.runners.core.SimpleDoFnRunner.outputWindowedValue(SimpleDoFnRunner.java:267)
at org.apache.beam.repackaged.direct_java.runners.core.SimpleDoFnRunner.access$900(SimpleDoFnRunner.java:79)
at org.apache.beam.repackaged.direct_java.runners.core.SimpleDoFnRunner$DoFnProcessContext.output(SimpleDoFnRunner.java:413)
at org.apache.beam.repackaged.direct_java.runners.core.SimpleDoFnRunner$DoFnProcessContext.output(SimpleDoFnRunner.java:401)
at com.company.Dataflow.DataFlowPipeline$1.processElement(Collector.java:100)
Caused by: java.lang.NullPointerException
at org.apache.avro.specific.SpecificDatumWriter.writeString(SpecificDatumWriter.java:67)
at org.apache.avro.generic.GenericDatumWriter.writeWithoutConversion(GenericDatumWriter.java:128)
at org.apache.avro.generic.GenericDatumWriter.write(GenericDatumWriter.java:75)
at org.apache.avro.reflect.ReflectDatumWriter.write(ReflectDatumWriter.java:159)
at org.apache.avro.generic.GenericDatumWriter.writeField(GenericDatumWriter.java:166)
at org.apache.avro.specific.SpecificDatumWriter.writeField(SpecificDatumWriter.java:90)
at org.apache.avro.reflect.ReflectDatumWriter.writeField(ReflectDatumWriter.java:191)
at org.apache.avro.generic.GenericDatumWriter.writeRecord(GenericDatumWriter.java:156)
at org.apache.avro.generic.GenericDatumWriter.writeWithoutConversion(GenericDatumWriter.java:118)
at org.apache.avro.generic.GenericDatumWriter.write(GenericDatumWriter.java:75)
at org.apache.avro.reflect.ReflectDatumWriter.write(ReflectDatumWriter.java:159)
at org.apache.avro.generic.GenericDatumWriter.writeField(GenericDatumWriter.java:166)
at org.apache.avro.specific.SpecificDatumWriter.writeField(SpecificDatumWriter.java:90)
at org.apache.avro.reflect.ReflectDatumWriter.writeField(ReflectDatumWriter.java:191)
at org.apache.avro.generic.GenericDatumWriter.writeRecord(GenericDatumWriter.java:156)
at org.apache.avro.generic.GenericDatumWriter.writeWithoutConversion(GenericDatumWriter.java:118)
at org.apache.avro.generic.GenericDatumWriter.write(GenericDatumWriter.java:75)
at org.apache.avro.reflect.ReflectDatumWriter.write(ReflectDatumWriter.java:159)
at org.apache.avro.generic.GenericDatumWriter.write(GenericDatumWriter.java:62)
at org.apache.beam.sdk.coders.AvroCoder.encode(AvroCoder.java:312)
at org.apache.beam.sdk.coders.IterableLikeCoder.encode(IterableLikeCoder.java:114)
at org.apache.beam.sdk.coders.IterableLikeCoder.encode(IterableLikeCoder.java:60)
at org.apache.beam.sdk.coders.Coder.encode(Coder.java:136)
at org.apache.beam.sdk.util.CoderUtils.encodeToSafeStream(CoderUtils.java:82)
at org.apache.beam.sdk.util.CoderUtils.encodeToByteArray(CoderUtils.java:66)
at org.apache.beam.sdk.util.CoderUtils.encodeToByteArray(CoderUtils.java:51)
at org.apache.beam.sdk.util.CoderUtils.clone(CoderUtils.java:141)
at org.apache.beam.sdk.util.MutationDetectors$CodedValueMutationDetector.<init>(MutationDetectors.java:115)
at org.apache.beam.sdk.util.MutationDetectors.forValueWithCoder(MutationDetectors.java:46)
at org.apache.beam.runners.direct.ImmutabilityCheckingBundleFactory$ImmutabilityEnforcingBundle.add(ImmutabilityCheckingBundleFactory.java:112)
at org.apache.beam.runners.direct.ParDoEvaluator$BundleOutputManager.output(ParDoEvaluator.java:300)
at org.apache.beam.repackaged.direct_java.runners.core.SimpleDoFnRunner.outputWindowedValue(SimpleDoFnRunner.java:267)
at org.apache.beam.repackaged.direct_java.runners.core.SimpleDoFnRunner.access$900(SimpleDoFnRunner.java:79)
at org.apache.beam.repackaged.direct_java.runners.core.SimpleDoFnRunner$DoFnProcessContext.output(SimpleDoFnRunner.java:413)
at org.apache.beam.repackaged.direct_java.runners.core.SimpleDoFnRunner$DoFnProcessContext.output(SimpleDoFnRunner.java:401)
at com.company.dataflow.DataFlowPipeline$1.processElement(Collector.java:100)
at com.company.dataflow.DataFlowPipeline$1$DoFnInvoker.invokeProcessElement(Unknown Source)
at org.apache.beam.repackaged.direct_java.runners.core.SimpleDoFnRunner.invokeProcessElement(SimpleDoFnRunner.java:227)
at org.apache.beam.repackaged.direct_java.runners.core.SimpleDoFnRunner.processElement(SimpleDoFnRunner.java:186)
at org.apache.beam.repackaged.direct_java.runners.core.SimplePushbackSideInputDoFnRunner.processElementInReadyWindows(SimplePushbackSideInputDoFnRunner.java:78)
at org.apache.beam.runners.direct.ParDoEvaluator.processElement(ParDoEvaluator.java:240)
at org.apache.beam.runners.direct.DoFnLifecycleManagerRemovingTransformEvaluator.processElement(DoFnLifecycleManagerRemovingTransformEvaluator.java:54)
at org.apache.beam.runners.direct.DirectTransformExecutor.processElements(DirectTransformExecutor.java:160)
at org.apache.beam.runners.direct.DirectTransformExecutor.run(DirectTransformExecutor.java:124)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Related
This question already has answers here:
Make Jackson interpret single JSON object as array with one element
(3 answers)
Deserializing json to pojo where json field has different data types
(2 answers)
Closed 1 year ago.
I have a JSON created by Elixir class which has a field which can be string or array:
field :logs, {:array, :string}
If anyone doesn't get this it will be like
{"logs" : "some log 1"}
or
{
"logs": ["some log 1", "some log 2"]
}
I have a Java field mapped for this:
#JsonProperty("logs")
private String logs;
This mapping works only when the logs comes as a String, but fails if the logs comes as array with error saying it will not be able to convert START_ARRAY to string.
How to serialize the field if it comes as array and store it as a comma separated string?
I see in tags that you use Jackson for parsing. This means you need to write and register with Jackson a custom deserializer for your logs field.
An example of such solution:
package tmp;
import java.io.IOException;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ValueNode;
public class JacksonDemo {
public static class LogHolder {
#JsonProperty("logs")
#JsonDeserialize(using = ArrayOrStringJsonDeserializer.class)
private String logs;
#Override
public String toString() {
return "LogHolder(logs=" + logs + ")";
}
}
public static class ArrayOrStringJsonDeserializer extends JsonDeserializer<String> {
#Override
public String deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException, JsonProcessingException {
JsonNode node = (JsonNode) jsonParser.readValueAsTree();
if (node.isValueNode()) {
ValueNode valueNode = (ValueNode) node;
if (valueNode.isTextual()) {
return valueNode.textValue();
}
} else if (node.isArray()) {
ArrayNode arrayNode = (ArrayNode) node;
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(arrayNode.iterator(), Spliterator.ORDERED), false)
.map(JsonNode::textValue)
.collect(Collectors.joining(", "));
}
throw MismatchedInputException.from(jsonParser, String.class,
"Expected node to be of type String or array, but got " + node.getNodeType().toString());
}
}
public static void main(String args[]) throws Exception {
String[] docs = { "{\"logs\" : \"some log 1\"}", "{\"logs\": [\"some log 1\", \"some log 2\"]}" };
ObjectMapper om = new ObjectMapper();
for (String doc : docs) {
System.out.println(om.readValue(doc, LogHolder.class));
}
}
}
Result of executing this code:
LogHolder(logs=some log 1)
LogHolder(logs=some log 1, some log 2)
I have written a java class to retrieve schema from schema registry using feignHttp. Above exception is thrown when I try to retrieve a schema.
Client class:
import com.google.gson.internal.LinkedTreeMap;
import feign.Feign;
import feign.FeignException;
import feign.gson.GsonDecoder;
import feign.gson.GsonEncoder;
import feign.okhttp.OkHttpClient;
import org.apache.avro.Schema;
import org.apache.avro.SchemaParseException;
public class SchemaRegistryReader {
public Schema getSchemaFromID(String registryURL, String schemaID) throws SchemaParseException, FeignException {
SchemaRegistryClient registryClient = Feign.builder()
.client(new OkHttpClient())
.encoder(new GsonEncoder())
.decoder(new GsonDecoder())
.target(SchemaRegistryClient.class, registryURL);
Object returnedSchema = registryClient.findByID(schemaID);
LinkedTreeMap jsonSchemaObject = ((LinkedTreeMap) returnedSchema);
String jsonSchema = jsonSchemaObject.get("schema").toString();
return new Schema.Parser().parse(jsonSchema);
}
}
Method Interface:
import feign.Headers;
import feign.Param;
import feign.RequestLine;
public interface SchemaRegistryClient {
#RequestLine("GET")
Object connect();
#RequestLine("GET /schemas/ids/{id}")
#Headers("Content-Type: application/json")
Object findByID(#Param("id") String id);
}
Exception thrown:
java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to com.google.gson.internal.LinkedTreeMap at org.wso2.extension.siddhi.map.avro.util.schema.SchemaRegistryReader.getSchemaFromID(SchemaRegistryReader.java:41)
Would be great help if the cause for this can be found.
I have a service consumer who wants my service to produce line delimited JSONL. How can I modify the Jackson parser or provide a custom serializer so that a retuned array of objects is serialized as JSONL and not JSON.
For example the following code
import java.util.Arrays;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
#SpringBootApplication
#RestController
public class JsonlServiceApplication {
public static void main(String[] args) {
SpringApplication.run(JsonlServiceApplication.class, args);
}
#GetMapping("jsonl")
private ResponseEntity<?> getJsonl(){
Pair<String, String> p1 = Pair.of("foo", "baa");
Pair<String, Integer> p2 = Pair.of("key", 10);
return new ResponseEntity(Arrays.asList(p1, p2), HttpStatus.OK);
}
}
Will produce this JSON:
[
{
"foo": "baa"
},
{
"key": 10
}
]
But the consumer would like:
{"foo": "baa"}
{"key": 10}
Maybe you can parse your json into an Object[] and iterate on each elem ? like that :
public static void main(String[] args) {
String json = "[{\"foo\":\"baa\"},{\"key\":10}]";
Gson gson = new Gson();
Object yourObj[] = gson.fromJson(json, Object[].class);
Arrays.stream(yourObj).forEach(e -> {
System.out.println(e);
});
}
Here are my bean classes:
package request;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
#JacksonXmlRootElement
public class Employee {
private List<String> roles= new ArrayList<String>();
private String name;
public Employee(){}
#JacksonXmlProperty
public String getName ()
{
return name;
}
public void setName (String name)
{
this.name = name;
}
#JacksonXmlElementWrapper(useWrapping=false)
#JacksonXmlProperty
public List<String> getRoles ()
{
return roleCodes;
}
public void setRoles (String role)
{
this.roles.add(role);
}
}
and,
package request;
import java.util.ArrayList;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
public class Employees
{
#JacksonXmlElementWrapper(localName="employees")
#JacksonXmlProperty(localName="employee")
private ArrayList<Employee> emps;
//Employee Employee ;
public Employees(){}
#JacksonXmlProperty(localName="employee")
public ArrayList<Employee> getEmployees ()
{
return emps;
}
public void setEmployees(Employee emp){
this.emps.add(emp);
}
#Override
public String toString()
{
if(emps.isEmpty()!=true)
for (Employee e:emps)
return "this is [employee = "+e ;
return "none there";
}
public ArrayList<Employee> addingEmployee(Employee e){
this.emps.add(e);
return emps;
}
}
And here is the code to parse the xml into POJO:
package testPkg4;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import request.Bean;
import request.Employee;
import request.Employees;
public class Test4 {
public static void main(String[] args) {
XmlMapper xmlMapper = new XmlMapper();
//Bean value = new Bean();
Employees emps=new Employees();
try {
emps = xmlMapper.readValue(new File("D:\\workspace\\test\\src\\test\\resources\\employee.xml"),
Employees.class);
} catch (IOException ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
}
System.out.println(emps.getEmployees().get(0).getFirstName());
//System.out.println(e.getFirstName());
//System.out.println(emps.getEmployees().get(0).getThirdElement());
}
}
Now here is the error I am getting :
com.fasterxml.jackson.databind.JsonMappingException: N/A at [Source:
D:\workspace\test\src\test\resources\employee.xml; line: 5, column:
12] (through reference chain: request.Employees["employee"]) at
com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:277)
at
com.fasterxml.jackson.databind.deser.SettableBeanProperty._throwAsIOE(SettableBeanProperty.java:551)
at
com.fasterxml.jackson.databind.deser.SettableBeanProperty._throwAsIOE(SettableBeanProperty.java:532)
at
com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:108)
at
com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:276)
at
com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140)
at
com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3814)
at
com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2756)
at testPkg4.Test4.main(Test4.java:23) Caused by:
java.lang.NullPointerException at
request.Employees.setEmployees(Employees.java:31) at
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at
sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at
java.lang.reflect.Method.invoke(Unknown Source) at
com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:106)
... 5 more Exception in thread "main" java.lang.NullPointerException
at testPkg4.Test4.main(Test4.java:29)
while i am parsing thsi xml file:
<employees>
<employee>
<name>ASHISH</name>
<roles>MD</roles>
</employee>
<employee>
<name>BAHADUR</name>
<roles>CO</roles>
<roles>TM</roles>
</employee>
</employees>
Can anyone help me figure out what's the issue!
Found an useful tutorial to create custom untyped xml deserializer which helped me overcome it .
and in case of serialization create java classes from schema using jaxb2-maven-pluging as a build plug in .
org.codehaus.mojo
jaxb2-maven-plugin
1.5
xjc
-extension -npa -b ${project.basedir}/src/main/xsd/global.xjb
** if you are using jackson library then either replace the annotations with the jackson alternatives for jaxb annotaions . or register the jaxbannotation module into your serializer .
Here is the link for the gist that helped me .
I wrote the following JsonSerializer to let Jackson serialize an array of integers into JSON:
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
public class TalkIdsSerializer extends JsonSerializer<TalkIds> {
/**
* Serializes a TalkIds object into the following JSON string:
* Example: { "talk_ids" : [ 5931, 5930 ] }
*/
#Override
public void serialize(TalkIds talkIds, JsonGenerator jsonGenerator,
SerializerProvider provider)
throws IOException {
jsonGenerator.writeStartObject();
jsonGenerator.writeArrayFieldStart(TalkIds.API_DICTIONARY_KEY);
for (Integer talkId : talkIds.getTalkIds()) {
jsonGenerator.writeNumber(talkId);
}
jsonGenerator.writeEndArray();
jsonGenerator.writeEndObject();
}
}
The class is used here:
#JsonSerialize(using = TalkIdsSerializer.class)
public class TalkIds { /* ... */ }
I want test the behavior of the serializer and came up with the following:
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
public class TalkIdsSerializerTest {
protected final ArrayList<Integer> TALK_IDS =
new ArrayList<>(Arrays.asList(5931, 5930));
protected TalkIdsSerializer talkIdsSerializer;
#Before
public void setup() throws IOException {
talkIdsSerializer = new TalkIdsSerializer();
}
#Test
public void testSerialize() throws IOException {
StringWriter stringWriter = new StringWriter();
JsonGenerator jsonGenerator =
new JsonFactory().createGenerator(stringWriter);
TalkIds talkIds = new TalkIds();
talkIds.add(TALK_IDS);
talkIdsSerializer.serialize(talkIds, jsonGenerator, null);
String string = stringWriter.toString(); // string is ""
assertNotNull(string);
assertTrue(string.length() > 0);
stringWriter.close();
}
}
However, nothing is written to the StringWriter. What am I doing wrong?
You need to flush() the generator
Method called to flush any buffered content to the underlying target (output stream, writer), and to flush the target itself as well.
http://fasterxml.github.io/jackson-core/javadoc/2.1.0/com/fasterxml/jackson/core/JsonGenerator.html#flush()
I had a similar requirement, to test a custom serializer. I used objectMapper to get the string directly(since you have already annotated TalkIds with JsonSerialize). You can get the json string from the object as follows
String json = new ObjectMapper().writeValueAsString(talkIds)
For me flush() changed nothing, so I changed the way to test it, in accordance with http://www.baeldung.com/jackson-custom-serialization.
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import java.io.StringWriter;
//...
#Test
public void serialize_custom() throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(MyCustomSerializer.class, myCustomSerializer);
objectMapper.registerModule(module);
StringWriter stringWriter = new StringWriter();
TalkIds talkIds = new TalkIds();
talkIds.add(TALK_IDS);
objectMapper.writeValue(stringWriter,wi);
assertTrue(stringWriter.toString().length() > 3);
}