Skip to content

Commit

Permalink
#1045: Remove GSON dependency.
Browse files Browse the repository at this point in the history
Signed-off-by: Michał Wadowski <Michal.Wadowski@orange.com>
Also-by: Simon Bernard <sbernard@sierrawireless.com>
  • Loading branch information
Michał Wadowski authored and sbernard31 committed Oct 25, 2021
1 parent d2aed76 commit 3d2b1f9
Show file tree
Hide file tree
Showing 21 changed files with 769 additions and 480 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
* Contributors:
* Sierra Wireless - initial API and implementation
* Achim Kraus (Bosch Software Innovations GmbH) - add json as storage format
* Orange - keep one JSON dependency
*******************************************************************************/
package org.eclipse.leshan.server.bootstrap.demo;

Expand All @@ -21,26 +22,29 @@
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.lang.reflect.Type;
import java.util.EnumSet;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.eclipse.leshan.core.request.BindingMode;
import org.eclipse.leshan.core.util.Validate;
import org.eclipse.leshan.server.bootstrap.BootstrapConfig;
import org.eclipse.leshan.server.bootstrap.EditableBootstrapConfigStore;
import org.eclipse.leshan.server.bootstrap.InMemoryBootstrapConfigStore;
import org.eclipse.leshan.server.bootstrap.InvalidConfigurationException;
import org.eclipse.leshan.server.bootstrap.demo.json.BindingModeTypeAdapter;
import org.eclipse.leshan.server.bootstrap.demo.json.ByteArraySerializer;
import org.eclipse.leshan.server.bootstrap.demo.json.EnumSetDeserializer;
import org.eclipse.leshan.server.bootstrap.demo.json.EnumSetSerializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.type.CollectionType;

/**
* A {@link EditableBootstrapConfigStore} which persist configuration in a file using json format.
Expand All @@ -58,8 +62,7 @@ public class JSONFileBootstrapStore extends InMemoryBootstrapConfigStore {
public static final String DEFAULT_FILE = "data/bootstrap.json";

private final String filename;
private final Gson gson;
private final Type gsonType;
private final ObjectMapper mapper;

public JSONFileBootstrapStore() {
this(DEFAULT_FILE);
Expand All @@ -70,14 +73,19 @@ public JSONFileBootstrapStore() {
*/
public JSONFileBootstrapStore(String filename) {
Validate.notEmpty(filename);
GsonBuilder builder = new GsonBuilder();
builder.setPrettyPrinting();
builder.registerTypeAdapter(new TypeToken<EnumSet<BindingMode>>() {
}.getType(), new BindingModeTypeAdapter());

this.gson = builder.create();
this.gsonType = new TypeToken<Map<String, BootstrapConfig>>() {
}.getType();

mapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT);
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
mapper.enable(SerializationFeature.INDENT_OUTPUT);
SimpleModule module = new SimpleModule();
module.addDeserializer(EnumSet.class, new EnumSetDeserializer());

CollectionType collectionType = mapper.getTypeFactory().constructCollectionType(EnumSet.class, Object.class);
module.addSerializer(new EnumSetSerializer(collectionType));

module.addSerializer(new ByteArraySerializer(ByteArraySerializer.ByteMode.SIGNED));
mapper.registerModule(module);

this.filename = filename;
this.loadFromFile();
}
Expand Down Expand Up @@ -125,7 +133,9 @@ private void loadFromFile() {
File file = new File(filename);
if (file.exists()) {
try (InputStreamReader in = new InputStreamReader(new FileInputStream(file))) {
Map<String, BootstrapConfig> configs = gson.fromJson(in, gsonType);
TypeReference<Map<String, BootstrapConfig>> bootstrapConfigTypeRef = new TypeReference<Map<String, BootstrapConfig>>() {
};
Map<String, BootstrapConfig> configs = mapper.readValue(in, bootstrapConfigTypeRef);
for (Map.Entry<String, BootstrapConfig> config : configs.entrySet()) {
addToStore(config.getKey(), config.getValue());
}
Expand All @@ -151,7 +161,7 @@ private void saveToFile() {

// Write file
try (OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(filename))) {
out.write(gson.toJson(getAll(), gsonType));
out.write(mapper.writeValueAsString(getAll()));
}
} catch (Exception e) {
LOG.error("Could not save bootstrap infos to file", e);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*******************************************************************************
* Copyright (c) 2021 Orange.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v20.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.html.
*
* Contributors:
* Orange - keep one JSON dependency
*******************************************************************************/
package org.eclipse.leshan.server.bootstrap.demo.json;

import java.io.IOException;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;

public class ByteArraySerializer extends StdSerializer<byte[]> {

private static final long serialVersionUID = 1166117057647546937L;

private final ByteMode byteMode;

public enum ByteMode {
SIGNED, UNSIGNED
}

protected ByteArraySerializer(Class<byte[]> t, ByteMode byteMode) {
super(t);
this.byteMode = byteMode;
}

public ByteArraySerializer(ByteMode byteMode) {
this(byte[].class, byteMode);
}

@Override
public void serialize(byte[] value, JsonGenerator gen, SerializerProvider provider) throws IOException {
int[] output = new int[value.length];

int mask = byteMode == ByteMode.SIGNED ? -1 : 0xff;
for (int i = 0; i < value.length; i++) {
output[i] = value[i] & mask;
}
gen.writeArray(output, 0, output.length);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2020 Sierra Wireless and others.
* Copyright (c) 2021 Orange.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
Expand All @@ -11,7 +11,7 @@
* http://www.eclipse.org/org/documents/edl-v10.html.
*
* Contributors:
* Sierra Wireless - initial API and implementation
* Orange - keep one JSON dependency
*******************************************************************************/
package org.eclipse.leshan.server.bootstrap.demo.json;

Expand All @@ -20,19 +20,22 @@

import org.eclipse.leshan.core.request.BindingMode;

import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;

public class BindingModeTypeAdapter extends TypeAdapter<EnumSet<BindingMode>> {
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.node.TextNode;

public class EnumSetBindingModeDeserializer extends JsonDeserializer<EnumSet<BindingMode>> {
@Override
public void write(JsonWriter out, EnumSet<BindingMode> value) throws IOException {
out.value(BindingMode.toString(value));
}
public EnumSet<BindingMode> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {

@Override
public EnumSet<BindingMode> read(JsonReader in) throws IOException {
return BindingMode.parse(in.nextString());
TreeNode treeNode = p.getCodec().readTree(p);

if (treeNode instanceof TextNode) {
return BindingMode.parse(((TextNode) treeNode).asText());
} else {
return null;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*******************************************************************************
* Copyright (c) 2021 Orange.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v20.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.html.
*
* Contributors:
* Orange - keep one JSON dependency
*******************************************************************************/
package org.eclipse.leshan.server.bootstrap.demo.json;

import java.util.EnumSet;

import org.eclipse.leshan.core.request.BindingMode;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import com.fasterxml.jackson.databind.deser.std.EnumDeserializer;
import com.fasterxml.jackson.databind.util.EnumResolver;

public class EnumSetDeserializer extends JsonDeserializer<EnumSet<?>> implements ContextualDeserializer {

@Override
public EnumSet<BindingMode> deserialize(JsonParser p, DeserializationContext ctxt) {
return null;
}

@Override
public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) {
if (ctxt.getContextualType().getContentType().getRawClass() == BindingMode.class) {
return new EnumSetBindingModeDeserializer();
} else {
return buildDefaultEnumSetDeserializer(ctxt);
}
}

private com.fasterxml.jackson.databind.deser.std.EnumSetDeserializer buildDefaultEnumSetDeserializer(
DeserializationContext ctxt) {
JavaType contextualType = ctxt.getContextualType();
JavaType contentType = contextualType.getContentType();
DeserializationConfig config = ctxt.getConfig();

return new com.fasterxml.jackson.databind.deser.std.EnumSetDeserializer(contentType, new EnumDeserializer(
buildDefaultEnumResolver(ctxt), config.isEnabled(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS)));
}

protected EnumResolver buildDefaultEnumResolver(DeserializationContext ctxt) {
JavaType contextualType = ctxt.getContextualType();
JavaType contentType = contextualType.getContentType();
Class<?> rawClass = contentType.getRawClass();
DeserializationConfig config = ctxt.getConfig();

return EnumResolver.constructFor(config, rawClass);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*******************************************************************************
* Copyright (c) 2021 Orange.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v20.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.html.
*
* Contributors:
* Orange - keep one JSON dependency
*******************************************************************************/
package org.eclipse.leshan.server.bootstrap.demo.json;

import java.io.IOException;
import java.util.EnumSet;

import org.eclipse.leshan.core.request.BindingMode;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.PropertyName;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.introspect.BasicBeanDescription;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;

public class EnumSetSerializer extends StdSerializer<EnumSet<?>> {

private static final long serialVersionUID = 7456682518094775441L;

public EnumSetSerializer(JavaType type) {
super(type);
}

@SuppressWarnings("unchecked")
@Override
public void serialize(EnumSet<?> value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
if (value == null) {
gen.writeNull();
} else {
if (isBindingMode(gen, serializers)) {
gen.writeString(BindingMode.toString((EnumSet<BindingMode>) value));
} else {
defaultEnumSetSerializer(value, gen, serializers);
}
}
}

private void defaultEnumSetSerializer(EnumSet<?> value, JsonGenerator gen, SerializerProvider serializers)
throws IOException {
JavaType valueType = serializers.getConfig().constructType(value.getClass());
com.fasterxml.jackson.databind.ser.std.EnumSetSerializer enumSetSerializer = new com.fasterxml.jackson.databind.ser.std.EnumSetSerializer(
valueType);
enumSetSerializer.serialize(value, gen, serializers);
}

private boolean isBindingMode(JsonGenerator gen, SerializerProvider serializers) {
SerializationConfig config = serializers.getConfig();

JavaType currValue = config.constructType(gen.getCurrentValue().getClass());
BeanDescription beanDesc = config.introspect(currValue);

String currentName = gen.getOutputContext().getCurrentName();
JavaType primaryType = ((BasicBeanDescription) beanDesc).findProperty(new PropertyName(currentName))
.getPrimaryType();

return primaryType.hasContentType() && primaryType.getContentType().getRawClass() == BindingMode.class;
}
}

0 comments on commit 3d2b1f9

Please sign in to comment.