Jackson JsonNode with empty element key - jackson

I am using jackson-dataformat-xml (2.9) to parse an XML into JsonNode and then parse it to JSON
(the XML is very dynamic so that is why I am using JsonNode instead of binding to a POJO. e.g 'elementName' and 'id' names may vary).
It happens that during the JSON parsing phase, one of the element keys is empty string ("").
XML:
<elementName>
<id type="pid">abcdef123</id>
</elementName>
Parsing logic:
public Parser() {
ObjectMapper jsonMapper = new ObjectMapper();
XmlMapper xmlMapper = new XmlMapper(new XmlFactory(new WstxInputFactory()));
}
public InputStream parseXmlResponse(InputStream xmlStream) {
InputStream stream = null;
try {
JsonNode node = xmlMapper.readTree(xmlStream);
stream = new ByteArrayInputStream(jsonMapper.writer().writeValueAsBytes(node));
} catch (IOException e) {
e.printStackTrace();
}
return stream;
}
Json:
Result:
{
"elementName": {
"id": {
"type": "pid",
"": "abcdef123"
}
},
}
Expected:
{
"elementName": {
"id": {
"type": "pid",
"value": "abcdef123"
}
},
}
My idea is to find whenever I have the empty key "" and replace it with "value". Either at XML de-serialization or during JSON serialization.
I have tried to use default serializer, filter, but haven't got it working in a nice and concise way.
Suggestions are much appreciated.
Thank you for the help.
Possible Solution:
Based on #shoek suggestion I decided to write a custom serializer to avoid creating an intermediate object (ObjectNode) during the process.
edit: refactor based on the same solution proposed by #shoek.
public class CustomNode {
private JsonNode jsonNode;
public CustomNode(JsonNode jsonNode) {
this.jsonNode = jsonNode;
}
public JsonNode getJsonNode() {
return jsonNode;
}
}
public class CustomObjectsResponseSerializer extends StdSerializer<CustomNode> {
protected CustomObjectsResponseSerializer() {
super(CustomNode.class);
}
#Override
public void serialize(CustomNode node, JsonGenerator jgen, SerializerProvider provider) throws IOException {
convertObjectNode(node.getJsonNode(), jgen, provider);
}
private void convertObjectNode(JsonNode node, JsonGenerator jgen, SerializerProvider provider) throws IOException {
jgen.writeStartObject();
for (Iterator<String> it = node.fieldNames(); it.hasNext(); ) {
String childName = it.next();
JsonNode childNode = node.get(childName);
// XML parser returns an empty string as value name. Replacing it with "value"
if (Objects.equals("", childName)) {
childName = "value";
}
if (childNode instanceof ArrayNode) {
jgen.writeFieldName(childName);
convertArrayNode(childNode, jgen, provider);
} else if (childNode instanceof ObjectNode) {
jgen.writeFieldName(childName);
convertObjectNode(childNode, jgen, provider);
} else {
provider.defaultSerializeField(childName, childNode, jgen);
}
}
jgen.writeEndObject();
}
private void convertArrayNode(JsonNode node, JsonGenerator jgen, SerializerProvider provider) throws IOException {
jgen.writeStartArray();
for (Iterator<JsonNode> it = node.elements(); it.hasNext(); ) {
JsonNode childNode = it.next();
if (childNode instanceof ArrayNode) {
convertArrayNode(childNode, jgen, provider);
} else if (childNode instanceof ObjectNode) {
convertObjectNode(childNode, jgen, provider);
} else {
provider.defaultSerializeValue(childNode, jgen);
}
}
jgen.writeEndArray();
}
}

You also could simply post-process the JSON DOM, traverse to all objects, and rename the keys that are empty strings to "value".
Race condition: such a key may already exist, and must not be overwritten
(e.g. <id type="pid" value="existing">abcdef123</id>).
Usage:
(note: you should not silently suppress the exception and return null, but allow it to propagate so the caller can decide to catch and apply failover logic if required)
public InputStream parseXmlResponse(InputStream xmlStream) throws IOException {
JsonNode node = xmlMapper.readTree(xmlStream);
postprocess(node);
return new ByteArrayInputStream(jsonMapper.writer().writeValueAsBytes(node));
}
Post-processing:
private void postprocess(JsonNode jsonNode) {
if (jsonNode.isArray()) {
ArrayNode array = (ArrayNode) jsonNode;
Iterable<JsonNode> elements = () -> array.elements();
// recursive post-processing
for (JsonNode element : elements) {
postprocess(element);
}
}
if (jsonNode.isObject()) {
ObjectNode object = (ObjectNode) jsonNode;
Iterable<String> fieldNames = () -> object.fieldNames();
// recursive post-processing
for (String fieldName : fieldNames) {
postprocess(object.get(fieldName));
}
// check if an attribute with empty string key exists, and rename it to 'value',
// unless there already exists another non-null attribute named 'value' which
// would be overwritten.
JsonNode emptyKeyValue = object.get("");
JsonNode existing = object.get("value");
if (emptyKeyValue != null) {
if (existing == null || existing.isNull()) {
object.set("value", emptyKeyValue);
object.remove("");
} else {
System.err.println("Skipping empty key value as a key named 'value' already exists.");
}
}
}
}
Output: just as expected.
{
"elementName": {
"id": {
"type": "pid",
"value": "abcdef123"
}
},
}
EDIT: considerations on performance:
I did a test with a large XML file (enwikiquote-20200520-pages-articles-multistream.xml, en.wikiquote XML dump, 498.4 MB), 100 rounds, with following measured times (using deltas with System.nanoTime()):
average read time (File, SSD): 2870.96 ms (JsonNode node = xmlMapper.readTree(xmlStream);)
average postprocessing time: 0.04 ms (postprocess(node);)
average write time (memory): 0.31 ms (new ByteArrayInputStream(jsonMapper.writer().writeValueAsBytes(node));)
That's a fraction of a millisecond for an object tree build from a ~500 MB file - so performance is excellent and no concern.

I figured out that this behaviour can be achieved via configuration.
Here is the kotlin code but it's simple to convert to java
Just create xmlMapper with appropriate configuration
fun jacksonCreateXmlMapper(): XmlMapper {
val module = JacksonXmlModule()
module.setXMLTextElementName("value")
return XmlMapper(module)
}
For input
<products>
<product count="5">apple</product>
<product count="10">orange</product>
</products>
you get:
{
"product" : [ {
"count" : "5",
"value" : "apple"
}, {
"count" : "10",
"value" : "orange"
} ]
}

Copying to a new ObjectNode may solve your problem.
package com.example;
import java.util.Iterator;
import java.util.Objects;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.ValueNode;
public class Stackoverflow62009220 {
public static void main(String[] args) throws JsonProcessingException {
convert("{\"elementName\":{\"id\":{\"type\":\"pid\",\"\":\"abcdef123\"}}}");
convert("{\"array\":[1,99,3]}");
convert("{\"complex-array\":[null, 1, [3,7,5], {\"type\":\"pid\",\"\":\"abcdef123\"}]}");
}
private static void convert(String str) throws JsonProcessingException {
JsonNode input = (new ObjectMapper()).readTree(str);
System.out.println("in:");
System.out.println(input);
ObjectMapper mapper = new ObjectMapper();
ObjectNode obj = convertObjectNode(input, mapper);
String output = mapper.writer().writeValueAsString(obj);
System.out.println("out:");
System.out.println(output);
System.out.println("----------");
}
private static ArrayNode convertArrayNode(JsonNode current, ObjectMapper mapper) {
ArrayNode to = mapper.createArrayNode();
for (Iterator<JsonNode> it = current.elements(); it.hasNext();) {
JsonNode childNode = it.next();
if (childNode instanceof ValueNode) {
to.add(childNode);
} else if (childNode instanceof ArrayNode) {
// recurse
to.add(convertArrayNode(childNode, mapper));
} else if (childNode instanceof ObjectNode) {
to.add(convertObjectNode(childNode, mapper));
}
}
return to;
}
private static ObjectNode convertObjectNode(JsonNode current, ObjectMapper mapper) {
ObjectNode to = mapper.createObjectNode();
for (Iterator<String> it = current.fieldNames(); it.hasNext();) {
String childName = it.next();
JsonNode childNode = current.get(childName);
if (Objects.equals("", childName)) {
childName = "value";
}
if (childNode instanceof ValueNode) {
to.set(childName, childNode);
} else if (childNode instanceof ArrayNode) {
to.set(childName, convertArrayNode(childNode, mapper));
} else if (childNode instanceof ObjectNode) {
// recurse
to.set(childName, convertObjectNode(childNode, mapper));
}
}
return to;
}
}
The preceding code results in:
in:
{"elementName":{"id":{"type":"pid","":"abcdef123"}}}
out:
{"elementName":{"id":{"type":"pid","value":"abcdef123"}}}
----------
in:
{"array":[1,99,3]}
out:
{"array":[1,99,3]}
----------
in:
{"complex-array":[null,1,[3,7,5],{"type":"pid","":"abcdef123"}]}
out:
{"complex-array":[null,1,[3,7,5],{"type":"pid","value":"abcdef123"}]}
----------
P.S.
I couldn't find a way to use a custom serializer (like this) for non-typed JsonNode.
If someone knows, please post your answer. It may be a better solution with regard to memory usage/processing time.

Serializer version.
package com.example;
import java.io.IOException;
import java.util.Iterator;
import java.util.Objects;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.module.SimpleSerializers;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
public class Stackoverflow62009220_B {
public static void main(String[] args) throws JsonProcessingException {
// see https://www.baeldung.com/jackson-call-default-serializer-from-custom-serializer
convert("{\"elementName\":{\"id\":{\"type\":\"pid\",\"\":\"abcdef123\"}}}");
// j = {"":"is_empty_field","num":1,"str":"aa","null_val":null,"empty_val":"","array":[3,5],"obj":{"a":"A","b":22}}
// (simple json object)
String j = "{\"\":\"is_empty_field\",\"num\":1,\"str\":\"aa\",\"null_val\":null,\"empty_val\":\"\",\"array\":[3,5],\"obj\":{\"a\":\"A\",\"b\":22}}";
convert(j);
// g = {"":"is_empty_field","num":1,"str":"aa","null_val":null,"empty_val":"","array":[3,{"":"is_empty_field","num":1,"str":"aa","null_val":null,"empty_val":"","array":[3,5],"obj":{"a":"A","b":22}}],"obj":{"":"is_empty_field","num":1,"str":"aa","null_val":null,"empty_val":"","array":[3,5],"obj":{"a":"A","b":22}}}
// (includes an array containing object j, and an object j containing array)
String g = " {\"\":\"is_empty_field\",\"num\":1,\"str\":\"aa\",\"null_val\":null,\"empty_val\":\"\",\"array\":[3,{\"\":\"is_empty_field\",\"num\":1,\"str\":\"aa\",\"null_val\":null,\"empty_val\":\"\",\"array\":[3,5],\"obj\":{\"a\":\"A\",\"b\":22}}],\"obj\":{\"\":\"is_empty_field\",\"num\":1,\"str\":\"aa\",\"null_val\":null,\"empty_val\":\"\",\"array\":[3,5],\"obj\":{\"a\":\"A\",\"b\":22}}}";
convert(g);
}
private static void convert(String str) throws JsonProcessingException {
JsonNode input = (new ObjectMapper()).readTree(str);
System.out.println("in:");
System.out.println(input);
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
SimpleSerializers serializers = new SimpleSerializers();
serializers.addSerializer(ObjectNode.class, new MyObjectNodeSerializer());
module.setSerializers(serializers);
mapper.registerModule(module);
String output = mapper.writer().writeValueAsString(input);
System.out.println("out:");
System.out.println(output);
System.out.println("----------");
}
}
class MyObjectNodeSerializer extends StdSerializer<ObjectNode> {
public MyObjectNodeSerializer() {
super(ObjectNode.class);
}
public static MyObjectNodeSerializer create() {
return new MyObjectNodeSerializer();
}
#Override
public void serialize(ObjectNode value, JsonGenerator gen, SerializerProvider provider) throws IOException {
gen.writeStartObject();
for (Iterator<String> it = value.fieldNames(); it.hasNext();) {
String childName = it.next();
JsonNode childNode = value.get(childName);
if (Objects.equals("", childName)) {
childName = "value";
}
if (childNode instanceof ArrayNode) {
gen.writeFieldName(childName);
MyArrayNodeSerializer.create().serialize((ArrayNode) childNode, gen, provider);
} else if (childNode instanceof ObjectNode) {
gen.writeFieldName(childName);
this.serialize((ObjectNode) childNode, gen, provider);
} else {
provider.defaultSerializeField(childName, childNode, gen);
}
}
gen.writeEndObject();
}
}
class MyArrayNodeSerializer extends StdSerializer<ArrayNode> {
public MyArrayNodeSerializer() {
super(ArrayNode.class);
}
public static MyArrayNodeSerializer create() {
return new MyArrayNodeSerializer();
}
#Override
public void serialize(ArrayNode value, JsonGenerator gen, SerializerProvider provider) throws IOException {
gen.writeStartArray();
for (Iterator<JsonNode> it = value.elements(); it.hasNext();) {
JsonNode childNode = it.next();
if (childNode instanceof ArrayNode) {
this.serialize((ArrayNode) childNode, gen, provider);
} else if (childNode instanceof ObjectNode) {
MyObjectNodeSerializer.create().serialize((ObjectNode) childNode, gen, provider);
} else {
provider.defaultSerializeValue(childNode, gen);
}
}
gen.writeEndArray();
}
}

Related

Trouble in testing with invalid field

public with sharing class SobjectByParams {
public SObject createSObject(String sObjectName, Map<String, String> fields) {
String invalidSObjectError = System.Label.invalid_Sobject_Name;
String invalidFieldError = System.Label.Invalid_Sobject_Field;
SObject newObject;
try {
newObject = (SObject) Type.forName(sObjectName).newInstance();
} catch (NullPointerException ex) {
throw new InvalidTypeNameException(invalidSObjectError);
}
for (String field : fields.keySet()) {
try {
newObject.put(field, fields.get(field));
} catch (SObjectException ex) {
throw new InvalidTypeNameException(invalidFieldError);
}
}
insert newObject;
return newObject;
}
public class InvalidTypeNameException extends Exception {
}
}
#IsTest
public with sharing class SobjectByParamsTest {
SobjectByParams sobjectByParams;
private static final String TestName = 'TestName';
private static final String BCity = 'Lviv';
private static final String LastName = 'Kapo';
private static final String Email = 'email';
#IsTest
static void createSObject() {
SobjectByParams sobjectByParams = new SobjectByParams();
Map<String, String> fields = new Map<String, String>();
fields.put('BillingCity', BCity);
Test.startTest();
SObject result = sobjectByParams.createSObject(TestName, fields);
Test.stopTest();
System.assertEquals(BCity, result.get(BCity));
}
}
SobjectByParams.InvalidTypeNameException: invalidSobjectNameError - PROBLEM
TEST WORKING on 53.33% but I need min 80%
I don`t know how to fix my problem.
Shouldn't TestName be a sObject name like Contact? Does this code work when you run it normally, does it insert anything or throw? Check/fix that and then you probably need a negative test too.
Make second test method
#isTest
static void testPassingBadData() {
SobjectByParams sobjectByParams = new SobjectByParams();
Map<String, String> fields = new Map<String, String>();
fields.put('BillingCity', BCity);
try{
sobjectByParams.createSObject('NoSuchObjectInTheSystem', fields);
System.assert(false, 'This should have failed and thrown exception');
} catch(Exception e){
System.assert(e.getMessage().contains(Label.Invalid_Sobject_Field));
}
}

How to check whatsapp sticker is already added or not in react native?

I am facing an issue related to WhatsApp sticker implementation. I have used this library I want to check that particular sticker is already added or not in WhatsApp.
How can I achieve this? Please guide me.
I have used below file from this library. isPackageInstalled() function worked for me (Note : I just wanted this functionality only for Android)
package org.roborox.whatsapp;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.database.Cursor;
import android.net.Uri;
import androidx.annotation.NonNull;
public class WhitelistCheck {
private static final String AUTHORITY_QUERY_PARAM = "authority";
private static final String IDENTIFIER_QUERY_PARAM = "identifier";
private static String STICKER_APP_AUTHORITY = "sticker_pack_authority";// StickerContentProvider.authority;
public static String CONSUMER_WHATSAPP_PACKAGE_NAME = "com.whatsapp";
public static String INSTAGRAM_PACKAGE_NAME = "com.instagram.android";
public static String SMB_WHATSAPP_PACKAGE_NAME = "com.whatsapp.w4b";
private static String CONTENT_PROVIDER = ".provider.sticker_whitelist_check";
private static String QUERY_PATH = "is_whitelisted";
private static String QUERY_RESULT_COLUMN_NAME = "result";
public static boolean isWhitelisted(#NonNull Context context, #NonNull String identifier) {
try {
boolean consumerResult = isWhitelistedFromProvider(context, identifier, CONSUMER_WHATSAPP_PACKAGE_NAME);
boolean smbResult = isWhitelistedFromProvider(context, identifier, SMB_WHATSAPP_PACKAGE_NAME);
return consumerResult && smbResult;
} catch (Exception e) {
return false;
}
}
private static boolean isWhitelistedFromProvider(#NonNull Context context, #NonNull String identifier, String whatsappPackageName) {
final PackageManager packageManager = context.getPackageManager();
if (isPackageInstalled(whatsappPackageName, packageManager)) {
final String whatsappProviderAuthority = whatsappPackageName + CONTENT_PROVIDER;
final ProviderInfo providerInfo = packageManager.resolveContentProvider(whatsappProviderAuthority, PackageManager.GET_META_DATA);
// provider is not there.
if (providerInfo == null) {
return false;
}
final Uri queryUri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(whatsappProviderAuthority).appendPath(QUERY_PATH).
appendQueryParameter(AUTHORITY_QUERY_PARAM, BuildConfig.CONTENT_PROVIDER_AUTHORITY).appendQueryParameter(IDENTIFIER_QUERY_PARAM, identifier).build();
final Cursor cursor = context.getContentResolver().query(queryUri, null, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
final int whiteListResult = cursor.getInt(cursor.getColumnIndexOrThrow(QUERY_RESULT_COLUMN_NAME));
return whiteListResult == 1;
}
} else {
//if app is not installed, then don't need to take into its whitelist info into account.
return true;
}
return false;
}
public static boolean isPackageInstalled(String packageName, PackageManager packageManager) {
try {
final ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName, 0);
//noinspection SimplifiableIfStatement
if (applicationInfo != null) {
return applicationInfo.enabled;
} else {
return false;
}
} catch (PackageManager.NameNotFoundException e) {
return false;
}
}
public static boolean redirectToInstagram(Context context) {
final PackageManager packageManager = context.getPackageManager();
if (isPackageInstalled(INSTAGRAM_PACKAGE_NAME, packageManager)) {
Intent i = context.getPackageManager().getLaunchIntentForPackage(INSTAGRAM_PACKAGE_NAME);
context.startActivity(i);
return true;
} else {
return false;
}
}
}

RTC Programmatic Creation of Work Items with Plain Java Client

public class CreateWorkItem {
private static class LoginHandler implements ILoginHandler, ILoginInfo {
private String fUserId;
private String fPassword;
private LoginHandler(String userId, String password) {
fUserId= userId;
fPassword= password;
}
public String getUserId() {
return fUserId;
}
public String getPassword() {
return fPassword;
}
public ILoginInfo challenge(ITeamRepository repository) {
return this;
}
}
private static class WorkItemInitialization extends WorkItemOperation {
private String fSummary;
private ICategoryHandle fCategory;
public WorkItemInitialization(String summary, ICategoryHandle category) {
super("Initializing Work Item");
fSummary= summary;
fCategory= category;
}
#Override
protected void execute(WorkItemWorkingCopy workingCopy, IProgressMonitor monitor) throws TeamRepositoryException {
IWorkItem workItem= workingCopy.getWorkItem();
workItem.setHTMLSummary(XMLString.createFromPlainText(fSummary));
workItem.setCategory(fCategory);
}
}
public static void main(String[] args) {
boolean result;
TeamPlatform.startup();
try {
result= run(args);
} catch (TeamRepositoryException x) {
x.printStackTrace();
result= false;
} finally {
TeamPlatform.shutdown();
}
if (!result)
System.exit(1);
}
private static boolean run(String[] args) throws TeamRepositoryException {
if (args.length != 7) {
System.out.println("Usage: CreateWorkItem <repositoryURI> <userId> <password> <projectArea> <workItemType> <summary> <category>");
return false;
}
String repositoryURI= args[0];
String userId= args[1];
String password= args[2];
String projectAreaName= args[3];
String typeIdentifier= args[4];
String summary= args[5];
String categoryName= args[6];
ITeamRepository teamRepository= TeamPlatform.getTeamRepositoryService().getTeamRepository(repositoryURI);
teamRepository.registerLoginHandler(new LoginHandler(userId, password));
teamRepository.login(null);
IProcessClientService processClient= (IProcessClientService) teamRepository.getClientLibrary(IProcessClientService.class);
IAuditableClient auditableClient= (IAuditableClient) teamRepository.getClientLibrary(IAuditableClient.class);
IWorkItemClient workItemClient= (IWorkItemClient) teamRepository.getClientLibrary(IWorkItemClient.class);
URI uri= URI.create(projectAreaName.replaceAll(" ", "%20"));
IProjectArea projectArea= (IProjectArea) processClient.findProcessArea(uri, null, null);
if (projectArea == null) {
System.out.println("Project area not found.");
return false;
}
IWorkItemType workItemType= workItemClient.findWorkItemType(projectArea, typeIdentifier, null);
if (workItemType == null) {
System.out.println("Work item type not found.");
return false;
}
List path= Arrays.asList(categoryName.split("/"));
ICategoryHandle category= workItemClient.findCategoryByNamePath(projectArea, path, null);
if (category == null) {
System.out.println("Category not found.");
return false;
}
WorkItemInitialization operation= new WorkItemInitialization(summary, category);
IWorkItemHandle handle= operation.run(workItemType, null);
IWorkItem workItem= auditableClient.resolveAuditable(handle, IWorkItem.FULL_PROFILE, null);
System.out.println("Created work item " + workItem.getId() + ".");
teamRepository.logout();
return true;
}
}
**This is jazz.net' offical sample code. My question is how can I set value to "categoryName" in "private static boolean run(String[] args) throws TeamRepositoryException" function.In the Main fuction,there is nothing describing the "arg[]".Who can give me a sample to initial "categoryName" argument. **
The category name argument is something that is defined in the RTC CCM project against the timeline or the project. A sample for this is shown below.
These are the values that are expected in the Category Name Argument.
You can look into your project settings to get this information.

java.lang.StackOverflowError exception on nested objects primitive values in Java Object Serialization

I have RangeTreeIndex and RangeTreeNode class which I'm using to build the index and after inserting 2500 records, after that, I'm trying to save RangeTreeIndex object in the file where I'm receiving StackOverflowError, below is my entire code:
public class RangeTreeNode<T> implements Serializable {
private static final long serialVersionUID = -1;
public T key;
public Object data;
public RangeTreeNode<T> left;
public RangeTreeNode<T> right;
public RangeTreeNode() {
}
}
public class RangeTreeIndex implements Serializable {
private RangeTreeNode<Number> root;
private RangeTreeNode<Number> firstLeafNode;
private RangeTreeNode<Number> lastLeafNode;
private Number min;
private Number max;
public RangeTreeIndex() {
}
#Override
public int insert(Number key, Object values) {
Number newKey = new Double(key.doubleValue());
if (newKey.doubleValue() < min.doubleValue()) {
min = new Double(key.doubleValue());
}
if (newKey.doubleValue() > max.doubleValue()) {
max = new Double(key.doubleValue());
}
RangeTreeNode<Number> newNode = new RangeTreeNode<>(newKey, values);
this.root = this.insert(root, newNode);
if (firstLeafNode == null && lastLeafNode == null) {
firstLeafNode = newNode;
lastLeafNode = newNode;
} else if (newNode.key.doubleValue() < firstLeafNode.key.doubleValue()) {
firstLeafNode = newNode;
} else if (newNode.key.doubleValue() > lastLeafNode.key.doubleValue()) {
lastLeafNode = newNode;
}
return 1;
}
private RangeTreeNode<Number> insert(RangeTreeNode<Number> parentNode, RangeTreeNode<Number> newNode) {
if (parentNode == null) {
parentNode = newNode;
} else {
if (newNode.key.doubleValue() <= parentNode.key.doubleValue()) {
parentNode.left = insert(parentNode.left, newNode);
} else {
parentNode.right = insert(parentNode.right, newNode);
}
}
return parentNode;
}
}
public class Main {
public static void main(String args[]) throws IOException {
String filePath = "XYZ.jobject";
try (RandomAccessFile raf = new RandomAccessFile(filePath, "rw");
FileOutputStream fOut = new FileOutputStream(raf.getFD());
BufferedOutputStream bos = new BufferedOutputStream(fOut);
ObjectOutputStream oOut = new ObjectOutputStream(bos)) {
oOut.writeObject(preferenceIndex);
}
}
}
Below is the exception I'm receiving:
Exception in thread "Thread-5" java.lang.StackOverflowError
at java.lang.Double.doubleToLongBits(Double.java:836)
at java.io.Bits.putDouble(Bits.java:121)
at java.io.ObjectStreamClass$FieldReflector.getPrimFieldValues(ObjectStreamClass.java:2168)
at java.io.ObjectStreamClass.getPrimFieldValues(ObjectStreamClass.java:1389)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1533)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
...
...
...
...
Even if I'm using Apache commons-lang library class SerializationUtils.serialize with passing only a serializable object it throws the same error.
Can anyone faced this problem like that with primitive values?

org.apache.fop.fo.flow.ExternalGraphic catches and logs ImageException I want to handle myself

I am transforming an Image into pdf for test purposes.
To ensure that the Image is compatible with the printing process later on, I'm running a quick test print during the upload.
I'm creating a simple Test-PDF with a transformer. When I try to print an image with an incompatible format, the ImageManager of the transformer throws an ImageException, starting in the preloadImage() function:
public ImageInfo preloadImage(String uri, Source src)
throws ImageException, IOException {
Iterator iter = registry.getPreloaderIterator();
while (iter.hasNext()) {
ImagePreloader preloader = (ImagePreloader)iter.next();
ImageInfo info = preloader.preloadImage(uri, src, imageContext);
if (info != null) {
return info;
}
}
throw new ImageException("The file format is not supported. No ImagePreloader found for "
+ uri);
}
throwing it to:
public ImageInfo needImageInfo(String uri, ImageSessionContext session, ImageManager manager)
throws ImageException, IOException {
//Fetch unique version of the URI and use it for synchronization so we have some sort of
//"row-level" locking instead of "table-level" locking (to use a database analogy).
//The fine locking strategy is necessary since preloading an image is a potentially long
//operation.
if (isInvalidURI(uri)) {
throw new FileNotFoundException("Image not found: " + uri);
}
String lockURI = uri.intern();
synchronized (lockURI) {
ImageInfo info = getImageInfo(uri);
if (info == null) {
try {
Source src = session.needSource(uri);
if (src == null) {
registerInvalidURI(uri);
throw new FileNotFoundException("Image not found: " + uri);
}
info = manager.preloadImage(uri, src);
session.returnSource(uri, src);
} catch (IOException ioe) {
registerInvalidURI(uri);
throw ioe;
} catch (ImageException e) {
registerInvalidURI(uri);
throw e;
}
putImageInfo(info);
}
return info;
}
}
throwing it to :
public ImageInfo getImageInfo(String uri, ImageSessionContext session)
throws ImageException, IOException {
if (getCache() != null) {
return getCache().needImageInfo(uri, session, this);
} else {
return preloadImage(uri, session);
}
}
Finally it gets caught and logged in the ExternalGraphic.class:
/** {#inheritDoc} */
public void bind(PropertyList pList) throws FOPException {
super.bind(pList);
src = pList.get(PR_SRC).getString();
//Additional processing: obtain the image's intrinsic size and baseline information
url = URISpecification.getURL(src);
FOUserAgent userAgent = getUserAgent();
ImageManager manager = userAgent.getFactory().getImageManager();
ImageInfo info = null;
try {
info = manager.getImageInfo(url, userAgent.getImageSessionContext());
} catch (ImageException e) {
ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
eventProducer.imageError(this, url, e, getLocator());
} catch (FileNotFoundException fnfe) {
ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
eventProducer.imageNotFound(this, url, fnfe, getLocator());
} catch (IOException ioe) {
ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
eventProducer.imageIOError(this, url, ioe, getLocator());
}
if (info != null) {
this.intrinsicWidth = info.getSize().getWidthMpt();
this.intrinsicHeight = info.getSize().getHeightMpt();
int baseline = info.getSize().getBaselinePositionFromBottom();
if (baseline != 0) {
this.intrinsicAlignmentAdjust
= FixedLength.getInstance(-baseline);
}
}
}
That way it isn't accessible for me in my code that uses the transformer.
I tried to use a custom ErrorListener, but the transformer only registers fatalErrors to the ErrorListener.
Is there any way to access the Exception and handle it myself without changing the code of the library?
It was easier than I thought. Before I call the transformation I register a costum EventListener to the User Agent of the Fop I'm using. This Listener just stores the Information what kind of Event was triggered, so I can throw an Exception if it's an ImageError.
My Listener:
import org.apache.fop.events.Event;
import org.apache.fop.events.EventListener;
public class ImageErrorListener implements EventListener
{
private String eventKey = "";
private boolean imageError = false;
#Override
public void processEvent(Event event)
{
eventKey = event.getEventKey();
if(eventKey.equals("imageError")) {
imageError = true;
}
}
public String getEventKey()
{
return eventKey;
}
public void setEventKey(String eventKey)
{
this.eventKey = eventKey;
}
public boolean isImageError()
{
return imageError;
}
public void setImageError(boolean imageError)
{
this.imageError = imageError;
}
}
Use of the Listener:
// Start XSLT transformation and FOP processing
ImageErrorListener imageListener = new ImageErrorListener();
fop.getUserAgent().getEventBroadcaster().addEventListener(imageListener);
if (res != null)
{
transformer.transform(xmlDomStreamSource, res);
}
if(imageListener.isImageError()) {
throw new ImageException("");
}
fop is of the type Fop ,xmlDomStreamSource ist the xml-Source I want to transform and res is my SAXResult.