diff --git a/kernel/base/src/main/java/com/twosigma/beakerx/BaseBeakerXJsonSerializer.java b/kernel/base/src/main/java/com/twosigma/beakerx/BaseBeakerXJsonSerializer.java new file mode 100644 index 0000000000..7bd236e86a --- /dev/null +++ b/kernel/base/src/main/java/com/twosigma/beakerx/BaseBeakerXJsonSerializer.java @@ -0,0 +1,68 @@ +/* + * Copyright 2018 TWO SIGMA OPEN SOURCE, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.twosigma.beakerx; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.twosigma.beakerx.jvm.serialization.BeakerObjectConverter; +import com.twosigma.beakerx.table.TableDisplayToJson; + +import java.io.IOException; +import java.io.StringWriter; + +import static com.fasterxml.jackson.databind.SerializationFeature.WRITE_ENUMS_USING_TO_STRING; + +public abstract class BaseBeakerXJsonSerializer implements BeakerXJsonSerializer { + + private final ObjectMapper objectMapper; + private final BeakerObjectConverter serializer; + + public BaseBeakerXJsonSerializer() { + this.objectMapper = new ObjectMapper(); + this.objectMapper.enable(WRITE_ENUMS_USING_TO_STRING); + this.objectMapper.registerModule(TableDisplayToJson.tableDisplayModule()); + this.serializer = createSerializer(); + } + + protected abstract BeakerObjectConverter createSerializer(); + + @Override + public String toJson(Object value) { + StringWriter sw = new StringWriter(); + try { + JsonGenerator jgen = objectMapper.getFactory().createGenerator(sw); + boolean success = serializer.writeObject(value, jgen, true); + jgen.flush(); + sw.flush(); + if (success) { + return sw.toString(); + } else { + return value.toString(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public Object fromJson(String json) { + try { + return serializer.deserialize(objectMapper.readTree(json), objectMapper); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/kernel/base/src/main/java/com/twosigma/beakerx/DefaultBeakerXJsonSerializer.java b/kernel/base/src/main/java/com/twosigma/beakerx/DefaultBeakerXJsonSerializer.java index 11f36285d4..c89cb6e03d 100644 --- a/kernel/base/src/main/java/com/twosigma/beakerx/DefaultBeakerXJsonSerializer.java +++ b/kernel/base/src/main/java/com/twosigma/beakerx/DefaultBeakerXJsonSerializer.java @@ -15,49 +15,13 @@ */ package com.twosigma.beakerx; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.ObjectMapper; import com.twosigma.beakerx.jvm.serialization.BasicObjectSerializer; -import com.twosigma.beakerx.table.TableDisplayToJson; +import com.twosigma.beakerx.jvm.serialization.BeakerObjectConverter; -import java.io.IOException; -import java.io.StringWriter; - -import static com.fasterxml.jackson.databind.SerializationFeature.WRITE_ENUMS_USING_TO_STRING; - -public class DefaultBeakerXJsonSerializer implements BeakerXJsonSerializer { - - private final BasicObjectSerializer objectSerializer; - private ObjectMapper objectMapper; - - public DefaultBeakerXJsonSerializer() { - this.objectMapper = new ObjectMapper(); - objectMapper.enable(WRITE_ENUMS_USING_TO_STRING); - objectMapper.registerModule(TableDisplayToJson.tableDisplayModule()); - objectSerializer = new BasicObjectSerializer(); - } +public class DefaultBeakerXJsonSerializer extends BaseBeakerXJsonSerializer { @Override - public String toJson(Object value) { - try { - StringWriter sw = new StringWriter(); - JsonGenerator jgen = objectMapper.getFactory().createGenerator(sw); - objectSerializer.writeObject(value, jgen, true); - jgen.flush(); - sw.flush(); - return sw.toString(); - } catch (IOException e) { - throw new RuntimeException(e); - } + protected BeakerObjectConverter createSerializer() { + return new BasicObjectSerializer(); } - - @Override - public Object fromJson(String json) { - try { - return objectMapper.readValue(json, Object.class); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - } diff --git a/kernel/base/src/main/java/com/twosigma/beakerx/NamespaceClient.java b/kernel/base/src/main/java/com/twosigma/beakerx/NamespaceClient.java index b70794a8bc..61e672e092 100644 --- a/kernel/base/src/main/java/com/twosigma/beakerx/NamespaceClient.java +++ b/kernel/base/src/main/java/com/twosigma/beakerx/NamespaceClient.java @@ -17,7 +17,7 @@ import com.twosigma.beakerx.evaluator.InternalVariable; import com.twosigma.beakerx.jvm.object.SimpleEvaluationObject; -import com.twosigma.beakerx.kernel.KernelConfigurationFile; +import com.twosigma.beakerx.kernel.ConfigurationFile; import com.twosigma.beakerx.kernel.comm.Comm; import com.twosigma.beakerx.kernel.comm.TargetNamesEnum; @@ -170,12 +170,12 @@ public String getContext() { return this.autotranslationService.getContextAsString(); } - public static NamespaceClient create(String id, KernelConfigurationFile configurationFile, CommRepository commRepository) { + public static NamespaceClient create(String id, ConfigurationFile configurationFile, CommRepository commRepository) { return create(id, configurationFile, new DefaultBeakerXJsonSerializer(), commRepository); } public static NamespaceClient create(String id, - KernelConfigurationFile configurationFile, + ConfigurationFile configurationFile, BeakerXJsonSerializer serializer, CommRepository commRepository) { if (configurationFile.getContext().isPresent()) { diff --git a/kernel/base/src/main/java/com/twosigma/beakerx/jvm/serialization/BasicObjectSerializer.java b/kernel/base/src/main/java/com/twosigma/beakerx/jvm/serialization/BasicObjectSerializer.java index f70c600b6a..15effd4e0e 100644 --- a/kernel/base/src/main/java/com/twosigma/beakerx/jvm/serialization/BasicObjectSerializer.java +++ b/kernel/base/src/main/java/com/twosigma/beakerx/jvm/serialization/BasicObjectSerializer.java @@ -51,24 +51,24 @@ public class BasicObjectSerializer implements BeakerObjectConverter { public static final String TYPE_INTEGER = "integer"; - public static final String TYPE_LONG = "int64"; - public static final String TYPE_BIGINT = "bigint"; - public static final String TYPE_DOUBLE = "double"; - public static final String TYPE_STRING = "string"; + public static final String TYPE_LONG = "int64"; + public static final String TYPE_BIGINT = "bigint"; + public static final String TYPE_DOUBLE = "double"; + public static final String TYPE_STRING = "string"; public static final String TYPE_BOOLEAN = "boolean"; - public static final String TYPE_TIME = "time"; - public static final String TYPE_SELECT = "select"; + public static final String TYPE_TIME = "time"; + public static final String TYPE_SELECT = "select"; private final static Logger logger = LoggerFactory.getLogger(BasicObjectSerializer.class.getName()); - protected final Map types; - protected final List knownBeakerTypes; + protected final Map types; + protected final List knownBeakerTypes; protected final List supportedDeserializers; - protected final List supportedSerializers; + protected final List supportedSerializers; - protected final ThreadLocal> threadTypes; + protected final ThreadLocal> threadTypes; protected final ThreadLocal> threadDeserializers; - protected final ThreadLocal> threadSerializers; + protected final ThreadLocal> threadSerializers; protected boolean isListOfPrimitiveTypeMaps(Object o) { if (!(o instanceof Collection)) @@ -99,7 +99,6 @@ protected boolean isPrimitiveTypeMap(Object o) { } - protected boolean isPrimitiveTypeListOfList(Object o) { if (!(o instanceof Collection)) return false; @@ -135,13 +134,13 @@ public BasicObjectSerializer() { addTypeConversion("java.lang.Double", TYPE_DOUBLE); addTypeConversion("java.lang.Enum", TYPE_SELECT); addTypeConversion("java.lang.Float", TYPE_DOUBLE); - addTypeConversion("java.lang.Integer", TYPE_INTEGER); + addTypeConversion("java.lang.Integer", TYPE_INTEGER); addTypeConversion("java.lang.Long", TYPE_LONG); addTypeConversion("java.lang.Short", TYPE_INTEGER); addTypeConversion("java.lang.String", TYPE_STRING); addTypeConversion("java.lang.StringBuffer", TYPE_STRING); addTypeConversion("java.lang.StringBuilder", TYPE_STRING); - addTypeConversion("java.util.Date", TYPE_TIME); + addTypeConversion("java.util.Date", TYPE_TIME); addTypeConversion("java.util.concurrent.atomic.AtomicInteger", TYPE_INTEGER); addTypeConversion("java.util.concurrent.atomic.AtomicLong", TYPE_INTEGER); addTypeConversion("java.math.BigDecimal", TYPE_DOUBLE); @@ -156,49 +155,49 @@ public BasicObjectSerializer() { addTypeSerializer(new CollectionSerializer(this)); addTypeSerializer(new MapSerializer(this)); } - + @Override public String convertType(String tn) { - if (threadTypes.get()!=null && threadTypes.get().containsKey(tn)) + if (threadTypes.get() != null && threadTypes.get().containsKey(tn)) return threadTypes.get().get(tn); if (types.containsKey(tn)) return types.get(tn); return ""; } - + @Override public boolean isPrimitiveType(String tn) { - return types.containsKey(tn) || (threadTypes.get()!=null && threadTypes.get().containsKey(tn)); + return types.containsKey(tn) || (threadTypes.get() != null && threadTypes.get().containsKey(tn)); } @Override public boolean writeObject(Object obj, JsonGenerator jgen, boolean expand) - throws IOException { - - if (obj == null) { - jgen.writeNull(); - } else if ((obj instanceof TableDisplay) || - (obj instanceof EvaluationResult) || - (obj instanceof UpdatableEvaluationResult) || - (obj instanceof CodeCell) || - (obj instanceof ImageIcon) || - (obj instanceof Date) || - (obj instanceof BeakerDashboard) || - (obj instanceof BufferedImage) || - (obj instanceof TabbedOutputContainerLayoutManager) || - (obj instanceof GridOutputContainerLayoutManager) || - (obj instanceof CyclingOutputContainerLayoutManager) || - (obj instanceof DashboardLayoutManager) || - (obj instanceof OutputContainerCell) || - (obj instanceof OutputContainer) || - (obj instanceof EasyForm) || - (obj instanceof Color)) { - logger.debug("basic object"); - jgen.writeObject(obj); - } else - return runThreadSerializers(obj, jgen, expand) || runConfiguredSerializers(obj, - jgen, - expand); + throws IOException { + + if (obj == null) { + jgen.writeNull(); + } else if ((obj instanceof TableDisplay) || + (obj instanceof EvaluationResult) || + (obj instanceof UpdatableEvaluationResult) || + (obj instanceof CodeCell) || + (obj instanceof ImageIcon) || + (obj instanceof Date) || + (obj instanceof BeakerDashboard) || + (obj instanceof BufferedImage) || + (obj instanceof TabbedOutputContainerLayoutManager) || + (obj instanceof GridOutputContainerLayoutManager) || + (obj instanceof CyclingOutputContainerLayoutManager) || + (obj instanceof DashboardLayoutManager) || + (obj instanceof OutputContainerCell) || + (obj instanceof OutputContainer) || + (obj instanceof EasyForm) || + (obj instanceof Color)) { + logger.debug("basic object"); + jgen.writeObject(obj); + } else + return runThreadSerializers(obj, jgen, expand) || runConfiguredSerializers(obj, + jgen, + expand); return true; } @@ -217,23 +216,23 @@ public boolean runThreadSerializers(Object obj, JsonGenerator jgen, boolean expa } return false; } - + public boolean runConfiguredSerializers(Object obj, JsonGenerator jgen, boolean expand) throws IOException, JsonProcessingException { for (ObjectSerializer s : supportedSerializers) { - if (s.canBeUsed(obj, expand) && s.writeObject(obj, jgen, expand)) - return true; + if (s.canBeUsed(obj, expand) && s.writeObject(obj, jgen, expand)) + return true; } return false; } - + @Override public Object deserialize(JsonNode n, ObjectMapper mapper) { - if (n==null) + if (n == null) return null; - + Object obj = null; - - if(threadDeserializers.get()!=null) { + + if (threadDeserializers.get() != null) { for (ObjectDeserializer d : threadDeserializers.get()) { try { if (d.canBeUsed(n)) { @@ -244,12 +243,12 @@ public Object deserialize(JsonNode n, ObjectMapper mapper) { } } } catch (Exception e) { - logger.error("exception in thread deserialization",e); + logger.error("exception in thread deserialization", e); obj = null; } } } - if (obj!=null) + if (obj != null) return obj; for (ObjectDeserializer d : supportedDeserializers) { try { @@ -261,32 +260,36 @@ public Object deserialize(JsonNode n, ObjectMapper mapper) { } } } catch (Exception e) { - logger.error("exception in deserialization",e); + logger.error("exception in deserialization", e); obj = null; } } - - if (obj==null) { + + if (obj == null) { logger.debug("using standard deserialization"); try { - obj = mapper.readValue(n.asText(), Object.class); + if (n.isTextual()) { + obj = n.textValue(); + } else { + obj = mapper.readValue(n.asText(), Object.class); + } } catch (Exception e) { - logger.error("exception in auto deserialization",e); + logger.error("exception in auto deserialization", e); obj = null; } } return obj; } - + /* * (non-Javadoc) * These implement module behavior modification */ - + @Override public void addTypeConversion(String from, String to) { - types.put(from,to); + types.put(from, to); } @Override @@ -301,38 +304,38 @@ public void addTypeSerializer(ObjectSerializer o) { @Override public void addfTypeDeserializer(ObjectDeserializer o) { - supportedDeserializers.add(0,o); + supportedDeserializers.add(0, o); } @Override public void addfTypeSerializer(ObjectSerializer o) { - supportedSerializers.add(0,o); + supportedSerializers.add(0, o); } /* * (non-Javadoc) * These implement thread specific module behavior modification */ - + @Override public void addThreadSpecificTypeConversion(String from, String to) { - if (threadTypes.get()==null) - threadTypes.set(new HashMap()); - threadTypes.get().put(from, to); + if (threadTypes.get() == null) + threadTypes.set(new HashMap()); + threadTypes.get().put(from, to); } @Override public void addThreadSpecificTypeDeserializer(ObjectDeserializer o) { - if (threadDeserializers.get()==null) + if (threadDeserializers.get() == null) threadDeserializers.set(new ArrayList()); threadDeserializers.get().add(o); } @Override public void addThreadSpecificTypeSerializer(ObjectSerializer o) { - if (threadSerializers.get()==null) + if (threadSerializers.get() == null) threadSerializers.set(new ArrayList()); - threadSerializers.get().add(o); + threadSerializers.get().add(o); } /* @@ -352,16 +355,16 @@ public boolean writeObject(Object obj, JsonGenerator jgen, boolean expand) throw jgen.writeObject(obj); return true; } - + } - + class ListOfPrimitiveTypeMapsSerializer implements ObjectSerializer { private final BasicObjectSerializer parent; - + public ListOfPrimitiveTypeMapsSerializer(BasicObjectSerializer p) { parent = p; } - + @Override public boolean canBeUsed(Object obj, boolean expand) { return expand && isListOfPrimitiveTypeMaps(obj); @@ -374,15 +377,15 @@ public boolean writeObject(Object obj, JsonGenerator jgen, boolean expand) throw // convert this 'on the fly' to a datatable @SuppressWarnings("unchecked") Collection> co = (Collection>) obj; - TableDisplay t = new TableDisplay(co,parent); + TableDisplay t = new TableDisplay(co, parent); jgen.writeObject(t); return true; - } catch(Exception e) { + } catch (Exception e) { return false; } } } - + class PrimitiveTypeListOfListSerializer implements ObjectSerializer { @Override @@ -393,24 +396,24 @@ public boolean canBeUsed(Object obj, boolean expand) { @Override public boolean writeObject(Object obj, JsonGenerator jgen, boolean expand) throws JsonProcessingException, IOException { logger.debug("collection of collections"); - + Collection m = (Collection) obj; int max = 0; - + for (Object entry : m) { Collection e = (Collection) entry; if (max < e.size()) max = e.size(); } List columns = new ArrayList(); - for (int i=0; i> values = new ArrayList>(); for (Object entry : m) { Collection e = (Collection) entry; List l2 = new ArrayList(e); if (l2.size() < max) { - for (int i=l2.size(); i m = (Map) obj; - + + Map m = (Map) obj; + List columns = new ArrayList(); columns.add("Key"); columns.add("Value"); @@ -446,10 +449,10 @@ public boolean writeObject(Object obj, JsonGenerator jgen, boolean expand) throw Set eset = m.entrySet(); for (Object entry : eset) { - Entry e = (Entry) entry; + Entry e = (Entry) entry; List l = new ArrayList(); Object o = e.getKey(); - l.add(null==o?"null":o.toString()); + l.add(null == o ? "null" : o.toString()); l.add(e.getValue()); values.add(l); } @@ -465,7 +468,7 @@ public boolean writeObject(Object obj, JsonGenerator jgen, boolean expand) throw class ArraySerializer implements ObjectSerializer { private final BasicObjectSerializer parent; - + public ArraySerializer(BasicObjectSerializer p) { parent = p; } @@ -484,7 +487,7 @@ public boolean writeObject(Object obj, JsonGenerator jgen, boolean expand) throw for (int i = 0; i < length; ++i) { Object o = Array.get(obj, i); if (!parent.writeObject(o, jgen, false)) { - jgen.writeObject(o.toString()); + jgen.writeObject(o.toString()); } } jgen.writeEndArray(); @@ -494,7 +497,7 @@ public boolean writeObject(Object obj, JsonGenerator jgen, boolean expand) throw class CollectionSerializer implements ObjectSerializer { private final BasicObjectSerializer parent; - + public CollectionSerializer(BasicObjectSerializer p) { parent = p; } @@ -510,7 +513,7 @@ public boolean writeObject(Object obj, JsonGenerator jgen, boolean expand) throw // convert this 'on the fly' to an array of objects Collection c = (Collection) obj; jgen.writeStartArray(); - for(Object o : c) { + for (Object o : c) { if (!parent.writeObject(o, jgen, false)) jgen.writeObject(o.toString()); } @@ -521,31 +524,31 @@ public boolean writeObject(Object obj, JsonGenerator jgen, boolean expand) throw class MapSerializer implements ObjectSerializer { private final BasicObjectSerializer parent; - + public MapSerializer(BasicObjectSerializer p) { parent = p; } @Override public boolean canBeUsed(Object obj, boolean expand) { - return obj instanceof Map; + return obj instanceof Map; } @Override public boolean writeObject(Object obj, JsonGenerator jgen, boolean expand) throws JsonProcessingException, IOException { logger.debug("generic map"); // convert this 'on the fly' to a map of objects - Map m = (Map) obj; + Map m = (Map) obj; Set kset = m.keySet(); - if (kset.size()==0 || !(kset.iterator().next() instanceof String)) + if (kset.size() == 0 || !(kset.iterator().next() instanceof String)) jgen.writeObject(obj.toString()); else { jgen.writeStartObject(); for (Object k : kset) { - jgen.writeFieldName((null==k)?"null":k.toString()); + jgen.writeFieldName((null == k) ? "null" : k.toString()); if (!parent.writeObject(m.get(k), jgen, false)) - jgen.writeObject(m.get(k)!=null ? (m.get(k).toString()) : "null"); + jgen.writeObject(m.get(k) != null ? (m.get(k).toString()) : "null"); } jgen.writeEndObject(); } diff --git a/kernel/base/src/main/java/com/twosigma/beakerx/kernel/ConfigurationFile.java b/kernel/base/src/main/java/com/twosigma/beakerx/kernel/ConfigurationFile.java index 55d4a165e8..b0a338e7c7 100644 --- a/kernel/base/src/main/java/com/twosigma/beakerx/kernel/ConfigurationFile.java +++ b/kernel/base/src/main/java/com/twosigma/beakerx/kernel/ConfigurationFile.java @@ -15,10 +15,14 @@ */ package com.twosigma.beakerx.kernel; +import java.util.Optional; + /** * Information from the connection file from Jupyter. */ public interface ConfigurationFile { Config getConfig(); + + Optional getContext(); } diff --git a/kernel/base/src/test/java/com/twosigma/beakerx/NamespaceClientTest.java b/kernel/base/src/test/java/com/twosigma/beakerx/NamespaceClientTest.java index 39126df58f..f854ad5185 100644 --- a/kernel/base/src/test/java/com/twosigma/beakerx/NamespaceClientTest.java +++ b/kernel/base/src/test/java/com/twosigma/beakerx/NamespaceClientTest.java @@ -29,6 +29,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import static java.util.Arrays.asList; import static org.assertj.core.api.Assertions.assertThat; @@ -132,14 +134,16 @@ public static boolean isJSONValid(Object jsonInString) { public static class AutotranslationServiceTestImpl implements AutotranslationService { + private ConcurrentMap beakerx = new ConcurrentHashMap(); + @Override public String update(String name, String json) { - return null; + return beakerx.put(name, json); } @Override public String get(String name) { - return null; + return beakerx.get(name); } @Override diff --git a/kernel/base/src/test/java/com/twosigma/beakerx/jvm/object/UpdatableEvaluationResultTest.java b/kernel/base/src/test/java/com/twosigma/beakerx/jvm/object/UpdatableEvaluationResultTest.java index 2bb82993fa..9e7ae71411 100644 --- a/kernel/base/src/test/java/com/twosigma/beakerx/jvm/object/UpdatableEvaluationResultTest.java +++ b/kernel/base/src/test/java/com/twosigma/beakerx/jvm/object/UpdatableEvaluationResultTest.java @@ -66,7 +66,7 @@ public void deserialize_resultObjectHasPayload() throws Exception { boolean payload = true; ObjectMapper mapper = new ObjectMapper(); JsonNode actualObj = mapper.readTree( - "{\"type\":\"UpdatableEvaluationResult\",\"payload\":\"" + payload + "\"}"); + "{\"type\":\"UpdatableEvaluationResult\",\"payload\":" + payload + "}"); UpdatableEvaluationResult.DeSerializer deserializer = new UpdatableEvaluationResult.DeSerializer(new BasicObjectSerializer()); //when diff --git a/kernel/base/src/test/java/com/twosigma/beakerx/jvm/serialization/MapDeserializerTest.java b/kernel/base/src/test/java/com/twosigma/beakerx/jvm/serialization/MapDeserializerTest.java index 55d01b282b..8a89d4ba31 100644 --- a/kernel/base/src/test/java/com/twosigma/beakerx/jvm/serialization/MapDeserializerTest.java +++ b/kernel/base/src/test/java/com/twosigma/beakerx/jvm/serialization/MapDeserializerTest.java @@ -25,7 +25,7 @@ public class MapDeserializerTest { - private String json = "{\"k1\":\"1\",\"k2\":\"true\"}"; + private String json = "{\"k1\":\"1\",\"k2\":true}"; @Test public void deserialize_resultObjectHasValues() throws Exception { diff --git a/kernel/base/src/test/java/com/twosigma/beakerx/jvm/serialization/ResultsDeserializerTest.java b/kernel/base/src/test/java/com/twosigma/beakerx/jvm/serialization/ResultsDeserializerTest.java index d9793dcf2b..e98486052a 100644 --- a/kernel/base/src/test/java/com/twosigma/beakerx/jvm/serialization/ResultsDeserializerTest.java +++ b/kernel/base/src/test/java/com/twosigma/beakerx/jvm/serialization/ResultsDeserializerTest.java @@ -30,7 +30,7 @@ public class ResultsDeserializerTest { @Before public void setUp() throws Exception { payload = true; - json = "{\"type\":\"Results\",\"payload\":\"" + payload + "\"}"; + json = "{\"type\":\"Results\",\"payload\":" + payload + "}"; } @Test diff --git a/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/autotranslation/NSClientProxy.java b/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/autotranslation/NSClientProxy.java new file mode 100644 index 0000000000..9bb5ab3168 --- /dev/null +++ b/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/autotranslation/NSClientProxy.java @@ -0,0 +1,29 @@ +/* + * Copyright 2018 TWO SIGMA OPEN SOURCE, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.twosigma.beakerx.clojure.autotranslation; + +import com.twosigma.beakerx.BeakerXClientManager; + +public class NSClientProxy { + + public static Object get(String key) { + return BeakerXClientManager.get().get(key); + } + + public static void set(String key, Object value) { + BeakerXClientManager.get().set(key, value); + } +} diff --git a/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/evaluator/ClojureEvaluator.java b/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/evaluator/ClojureEvaluator.java index 300760bfcf..6934396008 100644 --- a/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/evaluator/ClojureEvaluator.java +++ b/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/evaluator/ClojureEvaluator.java @@ -25,6 +25,7 @@ import com.twosigma.beakerx.TryResult; import com.twosigma.beakerx.autocomplete.AutocompleteResult; import com.twosigma.beakerx.clojure.autocomplete.ClojureAutocomplete; +import com.twosigma.beakerx.clojure.autotranslation.NSClientProxy; import com.twosigma.beakerx.evaluator.BaseEvaluator; import com.twosigma.beakerx.evaluator.JobDescriptor; import com.twosigma.beakerx.evaluator.TempFolderFactory; @@ -168,7 +169,11 @@ private void init() { loader = ClojureClassLoaderFactory.newInstance(classPath, outDir); String loadFunctionPrefix = "run_str"; try { - String clojureInitScript = String.format(initScriptSource(), beaker_clojure_ns, shellId, loadFunctionPrefix); + String clojureInitScript = String.format(initScriptSource(), + beaker_clojure_ns, + shellId, + loadFunctionPrefix, + NSClientProxy.class.getName()); String ns = String.format("%1$s_%2$s", beaker_clojure_ns, shellId); clearClojureNamespace(ns); clojureLoadString = RT.var(ns, String.format("%1$s_%2$s", loadFunctionPrefix, shellId)); diff --git a/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/handlers/ClojureCommOpenHandler.java b/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/handlers/ClojureCommOpenHandler.java index ccc0ad2340..862a208b7f 100644 --- a/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/handlers/ClojureCommOpenHandler.java +++ b/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/handlers/ClojureCommOpenHandler.java @@ -15,6 +15,7 @@ */ package com.twosigma.beakerx.clojure.handlers; +import com.twosigma.beakerx.kernel.comm.AutotranslationHandler; import com.twosigma.beakerx.kernel.comm.KernelControlCommandListHandler; import com.twosigma.beakerx.kernel.comm.KernelControlInterrupt; import com.twosigma.beakerx.kernel.comm.TargetNamesEnum; @@ -29,6 +30,9 @@ public class ClojureCommOpenHandler extends CommOpenHandler{ new KernelControlInterrupt(kernel), new KernelControlCommandListHandler(kernel)}; + private Handler[] AUTOTRANSLATION_HANDLER = { + new AutotranslationHandler(kernel)}; + public ClojureCommOpenHandler(KernelFunctionality kernel) { super(kernel); } @@ -36,6 +40,8 @@ public ClojureCommOpenHandler(KernelFunctionality kernel) { public Handler[] getKernelControlChanelHandlers(String targetName){ if(TargetNamesEnum.KERNEL_CONTROL_CHANNEL.getTargetName().equalsIgnoreCase(targetName)){ return (Handler[]) KERNEL_CONTROL_CHANNEL_HANDLERS; + }else if (TargetNamesEnum.BEAKER_AUTOTRANSLATION.getTargetName().equalsIgnoreCase(targetName)) { + return (Handler[]) AUTOTRANSLATION_HANDLER; }else{ return (Handler[]) new Handler[0]; } diff --git a/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/kernel/Clojure.java b/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/kernel/Clojure.java index 44bb827de6..0e3f028fc5 100644 --- a/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/kernel/Clojure.java +++ b/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/kernel/Clojure.java @@ -75,18 +75,15 @@ public KernelHandler getKernelInfoHandler(Kernel kernel) { return new ClojureKernelInfoHandler(kernel); } - public static void main(final String[] args) throws InterruptedException, IOException { + public static void main(final String[] args) { KernelRunner.run(() -> { String id = uuid(); CommRepository beakerXCommRepository = new BeakerXCommRepository(); KernelConfigurationFile configurationFile = new KernelConfigurationFile(args); KernelSocketsFactoryImpl kernelSocketsFactory = new KernelSocketsFactoryImpl( configurationFile); - ClojureEvaluator evaluator = new ClojureEvaluator( - id, - id, - getKernelParameters(), - NamespaceClient.create(id, configurationFile, beakerXCommRepository)); + NamespaceClient namespaceClient = NamespaceClient.create(id, configurationFile, new ClojureBeakerXJsonSerializer(), beakerXCommRepository); + ClojureEvaluator evaluator = new ClojureEvaluator(id, id, getKernelParameters(), namespaceClient); return new Clojure(id, evaluator, kernelSocketsFactory, beakerXCommRepository); }); } diff --git a/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/kernel/ClojureBeakerXJsonSerializer.java b/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/kernel/ClojureBeakerXJsonSerializer.java new file mode 100644 index 0000000000..c8b1280ae1 --- /dev/null +++ b/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/kernel/ClojureBeakerXJsonSerializer.java @@ -0,0 +1,32 @@ +/* + * Copyright 2018 TWO SIGMA OPEN SOURCE, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.twosigma.beakerx.clojure.kernel; + +import com.twosigma.beakerx.BaseBeakerXJsonSerializer; +import com.twosigma.beakerx.jvm.serialization.BasicObjectSerializer; +import com.twosigma.beakerx.jvm.serialization.BeakerObjectConverter; + +public class ClojureBeakerXJsonSerializer extends BaseBeakerXJsonSerializer { + + @Override + protected BeakerObjectConverter createSerializer() { + BasicObjectSerializer serializer = new BasicObjectSerializer(); + serializer.addfTypeDeserializer(new ClojureCollectionDeserializer(serializer)); + serializer.addfTypeDeserializer(new ClojureMapDeserializer(serializer)); + serializer.addfTypeDeserializer(new ClojureTableDeserializer(serializer)); + return serializer; + } +} diff --git a/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/kernel/ClojureCollectionDeserializer.java b/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/kernel/ClojureCollectionDeserializer.java new file mode 100644 index 0000000000..d7eb9fac17 --- /dev/null +++ b/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/kernel/ClojureCollectionDeserializer.java @@ -0,0 +1,59 @@ +/* + * Copyright 2014 TWO SIGMA OPEN SOURCE, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.twosigma.beakerx.clojure.kernel; + +import clojure.lang.PersistentVector; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.twosigma.beakerx.jvm.serialization.BeakerObjectConverter; +import com.twosigma.beakerx.jvm.serialization.ObjectDeserializer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class ClojureCollectionDeserializer implements ObjectDeserializer { + + private final static Logger logger = LoggerFactory.getLogger(ClojureCollectionDeserializer.class.getName()); + + private final BeakerObjectConverter parent; + + public ClojureCollectionDeserializer(BeakerObjectConverter p) { + parent = p; + } + + @Override + public boolean canBeUsed(JsonNode n) { + return n.isArray(); + } + + @Override + public Object deserialize(JsonNode n, ObjectMapper mapper) { + List list = new ArrayList<>(); + for (int i = 0; i < n.size(); i++) { + try { + list.add(parent.deserialize(n.get(i), mapper)); + } catch (Exception e) { + logger.error(e.getMessage()); + } + } + Collection collection = PersistentVector.create(list); + return collection; + } + +} diff --git a/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/kernel/ClojureMapDeserializer.java b/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/kernel/ClojureMapDeserializer.java new file mode 100644 index 0000000000..786e58c80d --- /dev/null +++ b/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/kernel/ClojureMapDeserializer.java @@ -0,0 +1,57 @@ +/* + * Copyright 2014 TWO SIGMA OPEN SOURCE, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.twosigma.beakerx.clojure.kernel; + +import clojure.lang.PersistentArrayMap; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.twosigma.beakerx.jvm.serialization.BeakerObjectConverter; +import com.twosigma.beakerx.jvm.serialization.ObjectDeserializer; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + + +public class ClojureMapDeserializer implements ObjectDeserializer { + private final BeakerObjectConverter parent; + + public ClojureMapDeserializer(BeakerObjectConverter p) { + parent = p; + } + + @Override + public boolean canBeUsed(JsonNode n) { + return n.isObject() && (!n.has("type") || !parent.isKnownBeakerType(n.get("type").asText())); + } + + @Override + public Object deserialize(JsonNode n, ObjectMapper mapper) { + HashMap map = new HashMap(); + Iterator> entries = n.fields(); + while (entries.hasNext()) { + try { + Map.Entry ee = entries.next(); + map.put(ee.getKey(), parent.deserialize(ee.getValue(), mapper)); + } catch (Exception e) { + LoggerFactory.getLogger(this.getClass().getName()).error(e.getMessage()); + } + } + return PersistentArrayMap.create(map); + } +} diff --git a/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/kernel/ClojureTableDeserializer.java b/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/kernel/ClojureTableDeserializer.java new file mode 100644 index 0000000000..fedbfcaf65 --- /dev/null +++ b/kernel/clojure/src/main/java/com/twosigma/beakerx/clojure/kernel/ClojureTableDeserializer.java @@ -0,0 +1,66 @@ +/* + * Copyright 2014 TWO SIGMA OPEN SOURCE, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.twosigma.beakerx.clojure.kernel; + +import clojure.lang.PersistentArrayMap; +import clojure.lang.PersistentVector; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.twosigma.beakerx.jvm.serialization.BeakerObjectConverter; +import com.twosigma.beakerx.jvm.serialization.ObjectDeserializer; +import com.twosigma.beakerx.table.TableDisplay; +import com.twosigma.beakerx.table.serializer.TableDisplayDeSerializer; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class ClojureTableDeserializer implements ObjectDeserializer { + private final BeakerObjectConverter parent; + + public ClojureTableDeserializer(BeakerObjectConverter p) { + parent = p; + parent.addKnownBeakerType("TableDisplay"); + } + + @Override + public boolean canBeUsed(JsonNode n) { + return n.has("type") && n.get("type").asText().equals("TableDisplay"); + } + + @Override + @SuppressWarnings("unchecked") + public Object deserialize(JsonNode n, ObjectMapper mapper) { + + org.apache.commons.lang3.tuple.Pair deserializeObject = TableDisplayDeSerializer.getDeserializeObject(parent, n, mapper); + String subtype = deserializeObject.getLeft(); + if (subtype != null && subtype.equals(TableDisplay.DICTIONARY_SUBTYPE)) { + return PersistentArrayMap.create((Map) deserializeObject.getRight()); + } else if (subtype != null && subtype.equals(TableDisplay.LIST_OF_MAPS_SUBTYPE)) { + List> rows = (List>) deserializeObject.getRight(); + List oo = new ArrayList(); + for (Map row : rows) { + oo.add(PersistentArrayMap.create(row)); + } + return PersistentVector.create(oo); + } else if (subtype != null && subtype.equals(TableDisplay.MATRIX_SUBTYPE)) { + List> matrix = (List>) deserializeObject.getRight(); + return PersistentVector.create(matrix); + } + return deserializeObject.getRight(); + } +} diff --git a/kernel/clojure/src/main/resources/init_clojure_script.txt b/kernel/clojure/src/main/resources/init_clojure_script.txt index a36a993944..a427490b3a 100644 --- a/kernel/clojure/src/main/resources/init_clojure_script.txt +++ b/kernel/clojure/src/main/resources/init_clojure_script.txt @@ -14,4 +14,12 @@ ;; limitations under the License. ;; (ns %1$s_%2$s)(defn %3$s_%2$s [s] (binding [*ns* (find-ns '%1$s_%2$s)] (load-string s))) +(import '%4$s) (require '[clojure.repl :as repl_%2$s]) +(defn get-beakerx [key] (%4$s/get key)) +(defn set-beakerx [key value] (%4$s/set key value)) +(def beakerx-method-map {:get get-beakerx :set set-beakerx}) +(defn beakerx + ([method key] ((beakerx-method-map method) key)) + ([method key value] ((beakerx-method-map method) key value))) + diff --git a/kernel/clojure/src/test/java/com/twosigma/beakerx/clojure/kernel/ClojureAutotranslationTest.java b/kernel/clojure/src/test/java/com/twosigma/beakerx/clojure/kernel/ClojureAutotranslationTest.java new file mode 100644 index 0000000000..c6256e6562 --- /dev/null +++ b/kernel/clojure/src/test/java/com/twosigma/beakerx/clojure/kernel/ClojureAutotranslationTest.java @@ -0,0 +1,122 @@ +/* + * Copyright 2017 TWO SIGMA OPEN SOURCE, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.twosigma.beakerx.clojure.kernel; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.twosigma.beakerx.BeakerXCommRepositoryMock; +import com.twosigma.beakerx.KernelSetUpFixtureTest; +import com.twosigma.beakerx.NamespaceClient; +import com.twosigma.beakerx.NamespaceClientTest; +import com.twosigma.beakerx.clojure.evaluator.ClojureEvaluator; +import com.twosigma.beakerx.kernel.CloseKernelAction; +import com.twosigma.beakerx.kernel.Kernel; +import com.twosigma.beakerx.kernel.KernelSocketsFactory; +import com.twosigma.beakerx.kernel.comm.Comm; +import com.twosigma.beakerx.message.Message; +import org.junit.Test; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.Optional; + +import static com.twosigma.beakerx.MessageFactoryTest.getExecuteRequestMessage; +import static com.twosigma.beakerx.evaluator.EvaluatorResultTestWatcher.waitForIdleMessage; +import static com.twosigma.beakerx.evaluator.EvaluatorResultTestWatcher.waitForResult; +import static com.twosigma.beakerx.evaluator.EvaluatorTest.KERNEL_PARAMETERS; +import static com.twosigma.beakerx.evaluator.EvaluatorTest.getCacheFolderFactory; +import static com.twosigma.beakerx.evaluator.EvaluatorTest.getTestTempFolderFactory; +import static com.twosigma.beakerx.evaluator.TestBeakerCellExecutor.cellExecutor; +import static org.assertj.core.api.Assertions.assertThat; + +public class ClojureAutotranslationTest extends KernelSetUpFixtureTest { + + private NamespaceClientTest.AutotranslationServiceTestImpl autotranslationService; + + @Override + protected Kernel createKernel(String sessionId, KernelSocketsFactory kernelSocketsFactory, CloseKernelAction closeKernelAction) { + autotranslationService = new NamespaceClientTest.AutotranslationServiceTestImpl(); + NamespaceClient nc = new NamespaceClient(autotranslationService, new ClojureBeakerXJsonSerializer(), new BeakerXCommRepositoryMock()); + ClojureEvaluator evaluator = new ClojureEvaluator(sessionId, sessionId, cellExecutor(), getTestTempFolderFactory(), KERNEL_PARAMETERS, nc); + return new Clojure(sessionId, evaluator, kernelSocketsFactory, closeKernelAction, getCacheFolderFactory(), new BeakerXCommRepositoryMock()); + } + + @Test + public void autotranslationSetAndGet() throws Exception { + //given + String code = "" + + "(beakerx :set \"foo\" 123)\n" + + "(beakerx :get \"foo\" )"; + Message message = getExecuteRequestMessage(code); + //when + kernelSocketsService.handleMsg(message); + //then + Optional idleMessage = waitForIdleMessage(kernelSocketsService.getKernelSockets()); + assertThat(idleMessage).isPresent(); + Optional result = waitForResult(kernelSocketsService.getKernelSockets()); + verifySetAndGetResult(result.get()); + } + + private void verifySetAndGetResult(Message message) { + Map actual = ((Map) message.getContent().get(Comm.DATA)); + String value = (String) actual.get("text/plain"); + assertThat(value).isNotEmpty(); + assertThat(value).contains("123"); + } + + @Test + public void transformFromJsonToClojureObject() throws Exception { + //given + autotranslationService.update("person", persons()); + //when + String code = "(((beakerx :get \"person\") 1) \"firstName\")"; + Message message = getExecuteRequestMessage(code); + kernelSocketsService.handleMsg(message); + //then + Optional idleMessage = waitForIdleMessage(kernelSocketsService.getKernelSockets()); + assertThat(idleMessage).isPresent(); + Optional result = waitForResult(kernelSocketsService.getKernelSockets()); + verifyClojureObject(result.get()); + } + + private String persons() { + LinkedList maps = new LinkedList<>(); + maps.addFirst(person("Amanda", "Smith", 33)); + maps.addFirst(person("John", "Doe", 26)); + ObjectMapper objectMapper = new ObjectMapper(); + try { + return objectMapper.writeValueAsString(maps); + } catch (JsonProcessingException e) { + throw new RuntimeException(); + } + } + + private Map person(String firstName, String lastName, int age) { + HashMap hashMap = new HashMap(); + hashMap.put("firstName", firstName); + hashMap.put("lastName", lastName); + hashMap.put("age", age); + return hashMap; + } + + private void verifyClojureObject(Message message) { + Map actual = ((Map) message.getContent().get(Comm.DATA)); + String value = (String) actual.get("text/plain"); + assertThat(value).isNotEmpty(); + assertThat(value).contains("Amanda"); + } +} \ No newline at end of file diff --git a/kernel/scala/src/main/java/com/twosigma/beakerx/scala/kernel/ScalaBeakerXJsonSerializer.java b/kernel/scala/src/main/java/com/twosigma/beakerx/scala/kernel/ScalaBeakerXJsonSerializer.java index 3283f558fd..3444e9321d 100644 --- a/kernel/scala/src/main/java/com/twosigma/beakerx/scala/kernel/ScalaBeakerXJsonSerializer.java +++ b/kernel/scala/src/main/java/com/twosigma/beakerx/scala/kernel/ScalaBeakerXJsonSerializer.java @@ -15,9 +15,7 @@ */ package com.twosigma.beakerx.scala.kernel; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.twosigma.beakerx.BeakerXJsonSerializer; +import com.twosigma.beakerx.BaseBeakerXJsonSerializer; import com.twosigma.beakerx.jvm.serialization.BasicObjectSerializer; import com.twosigma.beakerx.jvm.serialization.BeakerObjectConverter; import com.twosigma.beakerx.scala.serializers.ScalaCollectionDeserializer; @@ -28,53 +26,11 @@ import com.twosigma.beakerx.scala.serializers.ScalaPrimitiveTypeListOfListSerializer; import com.twosigma.beakerx.scala.serializers.ScalaPrimitiveTypeMapSerializer; import com.twosigma.beakerx.scala.serializers.ScalaTableDeSerializer; -import com.twosigma.beakerx.table.TableDisplayToJson; -import java.io.IOException; -import java.io.StringWriter; - -import static com.fasterxml.jackson.databind.SerializationFeature.WRITE_ENUMS_USING_TO_STRING; - -public class ScalaBeakerXJsonSerializer implements BeakerXJsonSerializer { - - private final ObjectMapper objectMapper; - private final BeakerObjectConverter serializer; - - public ScalaBeakerXJsonSerializer() { - this.objectMapper = new ObjectMapper(); - this.objectMapper.enable(WRITE_ENUMS_USING_TO_STRING); - this.objectMapper.registerModule(TableDisplayToJson.tableDisplayModule()); - this.serializer = createSerializer(); - } +public class ScalaBeakerXJsonSerializer extends BaseBeakerXJsonSerializer { @Override - public String toJson(Object value) { - StringWriter sw = new StringWriter(); - try { - JsonGenerator jgen = objectMapper.getFactory().createGenerator(sw); - boolean success = serializer.writeObject(value, jgen, true); - jgen.flush(); - sw.flush(); - if (success) { - return sw.toString(); - } else { - return value.toString(); - } - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - @Override - public Object fromJson(String json) { - try { - return objectMapper.readValue(json, Object.class); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - private static BeakerObjectConverter createSerializer() { + protected BeakerObjectConverter createSerializer() { BasicObjectSerializer serializer = new BasicObjectSerializer(); serializer.addfTypeSerializer(new ScalaCollectionSerializer(serializer)); serializer.addfTypeSerializer(new ScalaMapSerializer(serializer)); @@ -86,5 +42,4 @@ private static BeakerObjectConverter createSerializer() { serializer.addfTypeDeserializer(new ScalaTableDeSerializer(serializer)); return serializer; } - } diff --git a/test/ipynb/clojure/autotranslation_between_kernels.ipynb b/test/ipynb/clojure/autotranslation_between_kernels.ipynb new file mode 100644 index 0000000000..3c8562be7b --- /dev/null +++ b/test/ipynb/clojure/autotranslation_between_kernels.ipynb @@ -0,0 +1,81 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%clojure\n", + "(beakerx :set \"foo\" 1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%clojure\n", + "(beakerx :get \"foo\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%javascript\n", + "beakerx.person = [{firstName:\"John\", lastName:\"Doe\", age:26}, {firstName:\"Amanda\", lastName:\"Smith\", age:33}]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%clojure\n", + "(((beakerx :get \"person\") 1) \"firstName\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Groovy", + "language": "groovy", + "name": "groovy" + }, + "language_info": { + "codemirror_mode": "groovy", + "file_extension": ".groovy", + "mimetype": "", + "name": "Groovy", + "nbconverter_exporter": "", + "version": "2.4.3" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": false, + "sideBar": false, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": false, + "toc_window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/test/ipynb/clojure/autotranslation_for_clojure.ipynb b/test/ipynb/clojure/autotranslation_for_clojure.ipynb new file mode 100644 index 0000000000..1b304e7640 --- /dev/null +++ b/test/ipynb/clojure/autotranslation_for_clojure.ipynb @@ -0,0 +1,88 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "(beakerx :set \"foo\" 1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "(beakerx :get \"foo\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%javascript\n", + "console.log(beakerx.foo)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%javascript\n", + "beakerx.foo = 2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "(beakerx :get \"foo\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Clojure", + "language": "clojure", + "name": "clojure" + }, + "language_info": { + "codemirror_mode": "Clojure", + "file_extension": ".clj", + "mimetype": "text/x-clojure", + "name": "Clojure", + "nbconverter_exporter": "", + "version": "1.9.0" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": false, + "sideBar": false, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": false, + "toc_window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}