Skip to content

Instantly share code, notes, and snippets.

@joyheron
Created July 2, 2020 09:27
Show Gist options
  • Save joyheron/1467e043c978d089457896a0e7baa66f to your computer and use it in GitHub Desktop.
Save joyheron/1467e043c978d089457896a0e7baa66f to your computer and use it in GitHub Desktop.
Migrating from Nashorn to graaljs
package my.lovely.pkg;
import org.complate.core.ComplateRenderer;
import org.complate.core.ComplateSource;
import org.complate.graal.GraalComplateRenderer;
import org.complate.spring.mvc.ComplateViewResolver;
import org.complate.spring.source.ResourceComplateSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
@Configuration
public class ComplateConfiguration {
private static final String GRAAL_HELPERS = "Graal";
@Bean
public ComplateSource complateSource(
@Value("classpath:/templates/complate/bundle.js") Resource resource) {
return new ResourceComplateSource(resource);
}
@Bean
public ComplateRenderer complateRenderer(ComplateSource source) {
/*
* Adding this binding makes the GraalHelper methods available to the JSX
* as `Graal.toObject` and `Graal.toArray`
*
* Since `Graal.toArray` is compatible with Nashorn `Java.from`, using
* `Graal.toArray` in place of `Java.from` may be sufficient to avoid
* having to set `js.nashorn-compat=true` if you do not need other
* compatibility features from Nashorn
*/
return return GraalComplateRenderer.of(source)
.withBinding(GRAAL_HELPERS, new GraalHelper())
.build();
}
@Bean
public ComplateViewResolver complateViewResolver(ComplateRenderer renderer) {
return new ComplateViewResolver(renderer);
}
}
package my.lovely.pkg;
import org.graalvm.polyglot.proxy.ProxyArray;
import org.graalvm.polyglot.proxy.ProxyObject;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class GraalHelper {
/**
* This is a helper which will try to convert any Java Collection to a
* JavaScript Array. The helper will also iterate over the Collection and
* try to convert any Java {@link Map} objects to JavaScript objects using
* the {@link #toObject(Object)} method.
*
* If the helper receives something which is not a {@link Collection},
* then it will return the argument without attempting any conversion.
*
* @param javaCollection
* @return converted JavaScript Array
*/
public Object toArray(Object javaCollection) {
if (!(javaCollection instanceof Collection)) {
return null;
}
Collection collection = (Collection) javaCollection;
return ProxyArray.fromList((List) collection.stream()
.map(this::toObject)
.collect(Collectors.toList()));
}
/**
* This is a helper which will try to convert any Java {@link Map} to a
* JavaScript Array.
*
* If the helper receives something which is not a {@link Map},
* then it will return the argument without attempting any conversion.
*
* @param javaObject
* @return converted JavaScript object
*/
public Object toObject(Object javaObject) {
if (!(javaObject instanceof Map)) {
return javaObject;
}
return ProxyObject.fromMap((Map) javaObject);
}
}
package my.lovely.pkg;
import org.graalvm.polyglot.proxy.ProxyArray;
import org.graalvm.polyglot.proxy.ProxyObject;
import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
class GraalHelperTest {
@Test
void toObject_calling_with_non_map_returns_the_object() {
// arrange
String object = "foo";
// assert
assertThat(new GraalHelper().toObject(object), is(object));
}
@Test
void toObject_calling_with_null_returns_null() {
assertThat(new GraalHelper().toObject(null), is(nullValue()));
}
@Test
void toObject_calling_with_map_converts_map() {
// arrange
Map<String, Object> objectMap = new HashMap<>();
objectMap.put("foo", "Foo");
List<String> complicatedObject = List.of("a", "b", "c");
objectMap.put("bar", complicatedObject);
// act
ProxyObject object = (ProxyObject) new GraalHelper().toObject(objectMap);
// assert
assertThat(object.getMember("foo"), is("Foo"));
assertThat(object.getMember("bar"), is(complicatedObject));
}
@Test
void toArray_calling_with_null_returns_null() {
assertThat(new GraalHelper().toArray(null), is(nullValue()));
}
@Test
void toArray_calling_with_list_returns_array() {
// arrange
List<String> list = List.of("a", "b", "c");
// act
ProxyArray array = (ProxyArray) new GraalHelper().toArray(list);
// assert
assertThat(array.get(0), is("a"));
assertThat(array.get(1), is("b"));
assertThat(array.get(2), is("c"));
}
@Test
void toArray_calling_with_list_of_maps_converts_to_objects() {
// arrange
var list = List.of(
Map.of("k1", "v1"),
Map.of("k2", "v2"),
Map.of("k3", "v3"));
// act
ProxyArray array = (ProxyArray) new GraalHelper().toArray(list);
ProxyObject v1 = (ProxyObject) array.get(0);
ProxyObject v2 = (ProxyObject) array.get(1);
ProxyObject v3 = (ProxyObject) array.get(2);
// assert
assertThat(v1.getMember("k1"), is("v1"));
assertThat(v2.getMember("k2"), is("v2"));
assertThat(v3.getMember("k3"), is("v3"));
}
@Test
void toArray_calling_with_sets_returns_array() {
// arrange
var set = Set.of("a", "b", "c");
// act
ProxyArray array = (ProxyArray) new GraalHelper().toArray(set);
Set<Object> elements = new HashSet<>();
for (int i = 0; i < array.getSize(); i++) {
elements.add(array.get(i));
}
// assert
assertThat(elements, containsInAnyOrder("a", "b", "c"));
}
@Test
void toArray_calling_set_with_map_also_converts_it_to_object() {
// arrange
var set = Set.of(Map.of("foo", "bar"));
// act
ProxyArray array = (ProxyArray) new GraalHelper().toArray(set);
// assert
assertThat(((ProxyObject) array.get(0)).getMember("foo"), is("bar"));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment