Skip to content

Commit

Permalink
Merge pull request #2043 from beyonnex-io/bugfix/array-header-js-mapping
Browse files Browse the repository at this point in the history
fixed JS mapping header serialization to string for array headers
  • Loading branch information
thjaeckle authored Oct 14, 2024
2 parents 8eeccc1 + 38e7f24 commit f33323b
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@
import org.eclipse.ditto.connectivity.api.ExternalMessageFactory;
import org.eclipse.ditto.connectivity.model.MessageMappingFailedException;
import org.eclipse.ditto.connectivity.service.mapping.MessageMapper;
import org.eclipse.ditto.json.JsonArray;
import org.eclipse.ditto.json.JsonArrayBuilder;
import org.eclipse.ditto.json.JsonFactory;
import org.eclipse.ditto.json.JsonObject;
import org.eclipse.ditto.json.JsonObjectBuilder;
import org.eclipse.ditto.json.JsonParseException;
import org.eclipse.ditto.protocol.Adaptable;
import org.eclipse.ditto.protocol.JsonifiableAdaptable;
import org.eclipse.ditto.protocol.ProtocolFactory;
Expand Down Expand Up @@ -112,13 +118,16 @@ private ExternalMessage getExternalMessageFromObject(final Adaptable adaptable,
final Object bytePayload = result.get(EXTERNAL_MESSAGE_BYTE_PAYLOAD);
final Object mappingHeaders = result.get(EXTERNAL_MESSAGE_HEADERS);

final Map<String, String> headers;
if (mappingHeaders != null && !(mappingHeaders instanceof Undefined)) {
headers = new HashMap<>();
final Map<String, String> headers = new HashMap<>();
if (mappingHeaders instanceof NativeObject nativeHeaders) {
toJsonObject(nativeHeaders)
.stream()
.forEach(header ->
headers.put(header.getKeyName(), header.getValue().formatAsString())
);
} else if (mappingHeaders != null && !(mappingHeaders instanceof Undefined)) {
final Map<?,?> jsHeaders = (Map<?,?>) mappingHeaders;
jsHeaders.forEach((key, value) -> headers.put(String.valueOf(key), String.valueOf(value)));
} else {
headers = Collections.emptyMap();
}

final ExternalMessageBuilder messageBuilder =
Expand All @@ -144,6 +153,44 @@ private ExternalMessage getExternalMessageFromObject(final Adaptable adaptable,
return messageBuilder.build();
}

@SuppressWarnings("unchecked")
private static JsonObject toJsonObject(final NativeObject nativeObject) {
final JsonObjectBuilder objectBuilder = JsonObject.newBuilder();
nativeObject.forEach((key, value) -> {
try {
if (value instanceof String) {
objectBuilder.set(key.toString(), JsonFactory.readFrom(value.toString()));
} else if (value instanceof NativeArray nativeArray) {
objectBuilder.set(key.toString(), toJsonArray(nativeArray));
} else if (value instanceof NativeObject nativeSubObject) {
objectBuilder.set(key.toString(), toJsonObject(nativeSubObject));
}
} catch (final JsonParseException e) {
objectBuilder.set(key.toString(), value.toString());
}
});
return objectBuilder.build();
}

@SuppressWarnings("unchecked")
private static JsonArray toJsonArray(final NativeArray nativeArray) {
final JsonArrayBuilder arrayBuilder = JsonArray.newBuilder();
nativeArray.forEach(item -> {
switch (item) {
case NativeObject nativeObject -> arrayBuilder.add(toJsonObject(nativeObject));
case NativeArray nativeSubArray -> arrayBuilder.add(toJsonArray(nativeSubArray));
default -> {
try {
arrayBuilder.add(JsonFactory.readFrom(item.toString()));
} catch (final JsonParseException e) {
arrayBuilder.add(item.toString());
}
}
}
});
return arrayBuilder.build();
}

private static Optional<ByteBuffer> convertToByteBuffer(final Object obj) {
if (obj instanceof NativeArrayBuffer nativeArrayBuffer) {
return Optional.of(ByteBuffer.wrap(nativeArrayBuffer.getBuffer()));
Expand All @@ -165,7 +212,7 @@ private static Optional<ByteBuffer> convertToByteBuffer(final Object obj) {
}
}
} catch (final ClassNotFoundException | NoSuchMethodException | SecurityException
| IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
| IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new IllegalStateException("Could not retrieve array values", e);
}
} else if (obj instanceof List<?>) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@

import javax.annotation.Nullable;

import org.apache.pekko.actor.ActorSystem;
import org.assertj.core.api.AutoCloseableSoftAssertions;
import org.eclipse.ditto.base.model.acks.AcknowledgementRequest;
import org.eclipse.ditto.base.model.common.DittoConstants;
import org.eclipse.ditto.base.model.common.HttpStatus;
import org.eclipse.ditto.base.model.headers.DittoHeaders;
Expand Down Expand Up @@ -74,8 +76,6 @@
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;

import org.apache.pekko.actor.ActorSystem;

/**
* Tests the {@link JavaScriptMessageMapperRhino} by initializing different mapping templates and ensuring that they
* work as expected.
Expand Down Expand Up @@ -165,6 +165,7 @@ public final class JavaScriptMessageMapperRhinoTest {
" // Insert your mapping logic here\n" +
" let headers = {};\n" +
" headers['correlation-id'] = dittoHeaders['correlation-id'];\n" +
" headers['requested-acks'] = dittoHeaders['requested-acks'];\n" +
" let textPayload = `Thing ID was: ${namespace}:${name}`;\n" +
" let bytePayload = null;\n" +
" let contentType = \"" + CONTENT_TYPE_PLAIN + "\";\n" +
Expand Down Expand Up @@ -1179,7 +1180,9 @@ public void testPlainJavascriptOutgoingMapping() {
.setAttributes(Attributes.newBuilder().set("foo", "bar").build())
.build();
final CreateThing createThing =
CreateThing.of(newThing, null, DittoHeaders.newBuilder().correlationId(correlationId).build());
CreateThing.of(newThing, null, DittoHeaders.newBuilder()
.acknowledgementRequest(AcknowledgementRequest.parseAcknowledgementRequest("foo"))
.correlationId(correlationId).build());
final Adaptable adaptable = DittoProtocolAdapter.newInstance().toAdaptable(createThing);

final long startTs = System.nanoTime();
Expand All @@ -1192,6 +1195,7 @@ public void testPlainJavascriptOutgoingMapping() {

assertThat(rawMessage.findContentType()).contains(CONTENT_TYPE_PLAIN);
assertThat(rawMessage.findHeader(HEADER_CORRELATION_ID)).contains(correlationId);
assertThat(rawMessage.findHeader("requested-acks")).contains("[\"foo\"]");
assertThat(rawMessage.isTextMessage()).isTrue();
assertThat(rawMessage.getTextPayload()).contains("Thing ID was: " + thingId);
});
Expand Down

0 comments on commit f33323b

Please sign in to comment.