Skip to content

Commit

Permalink
implement custom JsonDeserializer to support "property_" prefixed cus…
Browse files Browse the repository at this point in the history
…tom metadata
  • Loading branch information
Jonas Dickel committed Aug 6, 2024
1 parent 5ab8473 commit 3a3cf25
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 4 deletions.
12 changes: 8 additions & 4 deletions src/main/java/com/bynder/sdk/api/ApiFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,21 @@
*/
package com.bynder.sdk.api;

import java.io.IOException;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

import com.bynder.sdk.configuration.Configuration;
import com.bynder.sdk.configuration.HttpConnectionSettings;
import com.bynder.sdk.exception.BynderRuntimeException;
import com.bynder.sdk.model.Media;
import com.bynder.sdk.service.BynderClient;
import com.bynder.sdk.util.BooleanTypeAdapter;
import com.bynder.sdk.util.MediaTypeAdapter;
import com.bynder.sdk.util.StringConverterFactory;
import com.bynder.sdk.util.Utils;
import com.google.gson.GsonBuilder;

import okhttp3.OkHttpClient;
import okhttp3.OkHttpClient.Builder;
import okhttp3.Request;
Expand All @@ -22,10 +29,6 @@
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

import java.io.IOException;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

/**
* Factory to create API clients.
*/
Expand All @@ -51,6 +54,7 @@ public static BynderApi createBynderClient(final Configuration configuration) {
.addConverterFactory(GsonConverterFactory.create(
new GsonBuilder()
.registerTypeAdapter(Boolean.class, new BooleanTypeAdapter())
.registerTypeAdapter(Media.class, new MediaTypeAdapter())
.create())
)
.client(createOkHttpClient(configuration))
Expand Down
9 changes: 9 additions & 0 deletions src/main/java/com/bynder/sdk/model/Media.java
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ public class Media {
* versions equal to true.
*/
private List<MediaItem> mediaItems;
/**
* Custom properties not having an PropertyOption. Key is the property name and
* value the value(s) of that property.
*/
private Map<String, List<String>> customMetaproperties;

public String getId() {
return id;
Expand Down Expand Up @@ -216,4 +221,8 @@ public Map<String, Double> getFocusPoint() {
public List<MediaItem> getMediaItems() {
return mediaItems;
}

public Map<String, List<String>> getCustomMetaproperties() {
return customMetaproperties;
}
}
66 changes: 66 additions & 0 deletions src/main/java/com/bynder/sdk/util/MediaTypeAdapter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.bynder.sdk.util;

import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import com.bynder.sdk.model.Media;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;

public class MediaTypeAdapter implements JsonDeserializer<Media> {

private static final String PROPERTY_PREFIX = "property_";
private static final String CUSTOM_METAPROPERTY_FIELDNAME = "customMetaproperties";

private final Gson gson;

public MediaTypeAdapter() {
this.gson = new GsonBuilder().registerTypeAdapter(Boolean.class, new BooleanTypeAdapter()).create();
}

@Override
public Media deserialize(final JsonElement json, final Type typeOfT, final JsonDeserializationContext context)
throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
Media media = gson.fromJson(jsonObject, Media.class);

Map<String, List<String>> metaproperties = new LinkedHashMap<>();

for (Map.Entry<String, JsonElement> elementJson : jsonObject.entrySet()) {
if (elementJson.getKey().startsWith(PROPERTY_PREFIX)) {
String propertyName = elementJson.getKey().substring(PROPERTY_PREFIX.length());
List<String> values = metaproperties.getOrDefault(metaproperties, new ArrayList<>());
if (elementJson.getValue().isJsonArray()) {
for (JsonElement element : elementJson.getValue().getAsJsonArray()) {
values.add(element.getAsString());
}
} else {
values.add(elementJson.getValue().getAsString());
}
metaproperties.put(propertyName, values);
}
}
setMetaproperties(media, metaproperties);
return media;
}

private void setMetaproperties(Media media, Map<String, List<String>> metaproperties) {
try {
Field metapropertiesField = media.getClass().getDeclaredField(CUSTOM_METAPROPERTY_FIELDNAME);
metapropertiesField.setAccessible(true);
metapropertiesField.set(media, metaproperties);
} catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
// does not occur unless Media class is changed
}
}

}
75 changes: 75 additions & 0 deletions src/test/java/com/bynder/sdk/util/MediaTypeAdapterTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright (c) 2017 Bynder B.V. All rights reserved.
*
* Licensed under the MIT License. See LICENSE file in the project root for full license
* information.
*
* JUnit framework component copyright (c) 2002-2017 JUnit. All Rights Reserved. Licensed under
* Eclipse Public License - v 1.0. You may obtain a copy of the License at
* https://www.eclipse.org/legal/epl-v10.html.
*/
package com.bynder.sdk.util;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.util.Arrays;

import org.junit.Test;

import com.bynder.sdk.model.Media;
import com.google.gson.JsonParser;

/**
* Tests the {@link BooleanTypeAdapter} class methods.
*/
public class MediaTypeAdapterTest {


/**
* Given JSON
*
* {
* "id": "FF5DB884-5665-4127-88D0116D8EB379FE",
* "isPublic": 0,
* "property_Articlenumber": "16773",
* "property_Language": [
* "Neutral"
* ]
* }
*
*/
private final String givenApiResponse = "{ \"id\": \"FF5DB884-5665-4127-88D0116D8EB379FE\", \"isPublic\": 0, \"property_Articlenumber\": \"16773\", \"property_Language\": [ \"Neutral\" ]}";


/**
* Tests that
* {@link MediaTypeAdapter#deserialize(com.google.gson.JsonElement, java.lang.reflect.Type, com.google.gson.JsonDeserializationContext)}
* correctly converts all "property_" prefixed json fields into a custom Map<String,List<String>> when deserializing the Json response returned by the
* API.
*/
@Test
public void deserializeWithMediaTypeAdapter() {
MediaTypeAdapter mediaTypeAdapter = new MediaTypeAdapter();

Media actualMedia = mediaTypeAdapter.deserialize(JsonParser.parseString(givenApiResponse), null, null);

// common default field like ID
assertEquals("FF5DB884-5665-4127-88D0116D8EB379FE", actualMedia.getId());

// boolean using BooleanTypeAdapter inside MediaTypeAdapter
assertEquals(Boolean.FALSE, actualMedia.isPublic());

// new custom "property_" which is returned as string from API#

assertNotNull(actualMedia.getCustomMetaproperties());
assertTrue(actualMedia.getCustomMetaproperties().containsKey("Articlenumber"));
assertEquals(Arrays.asList("16773"), actualMedia.getCustomMetaproperties().get("Articlenumber"));

// new custom "property_" which is returned as array from API
assertNotNull(actualMedia.getCustomMetaproperties());
assertTrue(actualMedia.getCustomMetaproperties().containsKey("Language"));
assertEquals(Arrays.asList("Neutral"), actualMedia.getCustomMetaproperties().get("Language"));
}
}

0 comments on commit 3a3cf25

Please sign in to comment.