I'm using the Java Github API
from org.kohsuke.github
to retrieve a GHRepository
object. I'd like to serialize this object to JSON
. Is there a provided way of doing this within the org.kohsuke.github
client? Possibly using Jackson
?
Currently, when using jackson, I've had to create a custom pojo to avoid Jackson encountering null Map key's and values. I suspect this github library already has code to do this as I can see it serializing to JSON in GitHub.java
but I'm not seeing a publicly accessible means of leveraging this. The code below is iterating over all my repos in all my orgs to get the JSON representation of the repo which will then be stored in a database.
// Iterate over all orgs that I can see on enterprise
github.listOrganizations().withPageSize(100).forEach( org -> {
// Get all the repositories in an org
Map<String, GHRepository> ghRepositoryMap = org.getRepositories();
// Iterate over each repo object and serialize
for (Map.Entry<String, GHRepository> entry :ghRepositoryMap.entrySet() ) {
// Serialize to JSON
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); //Handles null fields ok
String jsonStr = objectMapper.writeValueAsString(entry.getValue()); // <-- this fails due to null key
}
}
The last line results in :
com.fasterxml.jackson.databind.JsonMappingException: Null key for a Map not allowed in JSON (use a converting NullKeySerializer?) (through reference chain: org.kohsuke.github.GHRepository["responseHeaderFields"]->java.util.Collections$UnmodifiableMap["null"])
From inspection I believe this isn't the only null
key. I could probably customize the heck out of this by adding mixins to handle them but I'm looking for a built in way within the org.kohsuke.github
library that makes this easier since it appears to be capable of doing this internally.
You should implement and register NullKeySerializer
. See below example:
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class JsonApp {
public static void main(String[] args) throws Exception {
Map<String, List<String>> map = new HashMap<>();
map.put(null, Arrays.asList("A", "B", "C"));
map.put("regular-key", Arrays.asList("X", "Y"));
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
mapper.getSerializerProvider().setNullKeySerializer(new NullKeySerializer());
System.out.println(mapper.writeValueAsString(map));
}
}
class NullKeySerializer extends JsonSerializer<Object> {
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeFieldName("null");
}
}
Above code prints:
{
"null" : [ "A", "B", "C" ],
"regular-key" : [ "X", "Y" ]
}
Also, you should not create ObjectMapper
instance for each entry. You can create it once and use for all elements.