Last active
November 25, 2021 16:42
-
-
Save michael-simons/556dd49744aae99a72aa466bd3b832a0 to your computer and use it in GitHub Desktop.
A better Date Proxy to expose java.util.Date or java.time.Instant into GraalVMs JS embedding.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
///usr/bin/env jbang "$0" "$@" ; exit $? | |
//JAVA 17 | |
//DEPS org.graalvm.sdk:graal-sdk:21.3.0 | |
//DEPS org.assertj:assertj-core:3.21.0 | |
// Only needed when running on vanilla JVM | |
//DEPS org.graalvm.js:js:21.3.0 | |
package example; | |
import static org.assertj.core.api.Assertions.assertThat; | |
import java.time.Instant; | |
import java.time.LocalDate; | |
import java.time.ZoneId; | |
import java.util.Date; | |
import java.util.Set; | |
import org.graalvm.polyglot.Context; | |
import org.graalvm.polyglot.Value; | |
import org.graalvm.polyglot.proxy.ProxyExecutable; | |
import org.graalvm.polyglot.proxy.ProxyInstant; | |
import org.graalvm.polyglot.proxy.ProxyObject; | |
public class Application { | |
public static void main(String... a) { | |
try (var context = Context.newBuilder("js").build()) { | |
var today = LocalDate.now(); | |
var bindings = context.getBindings("js"); | |
bindings.putMember("javaInstant", new DateProxy(today.atStartOfDay().atZone(ZoneId.of("Europe/Berlin")).toInstant())); | |
bindings.putMember("yesterday", new DateProxy(today.minusDays(1).atStartOfDay().atZone(ZoneId.of("Europe/Berlin")).toInstant())); | |
var result = context.eval("js", | |
""" | |
var nativeDate = new Date(new Date().toLocaleString("en-US", {timeZone: "Europe/Berlin"})); | |
nativeDate.setHours(12); | |
nativeDate.setMinutes(0); | |
nativeDate.setSeconds(0); | |
nativeDate.setMilliseconds(0); | |
javaInstant.setHours(12); | |
({ | |
nativeDate : nativeDate, | |
nativeTimeFromNativeDate : nativeDate.getTime(), | |
javaInstant: javaInstant, | |
diff: nativeDate.getTime() - javaInstant.getTime(), | |
isBefore: yesterday < nativeDate, | |
nextWeek: new Date(javaInstant.setDate(javaInstant.getDate() + 7)) | |
}) | |
"""); | |
assertThat(result.getMember("nativeDate").asDate()).isEqualTo(today); | |
assertThat(result.getMember("diff").asLong()).isZero(); | |
assertThat(result.getMember("isBefore").asBoolean()).isTrue(); | |
assertThat(result.getMember("nextWeek").asDate()).isEqualTo(today.plusWeeks(1)); | |
} | |
} | |
@SuppressWarnings("deprecation") | |
public static class DateProxy implements ProxyObject, ProxyInstant { | |
private static final Set<String> PROTOTYPE_FUNCTIONS = Set.of( | |
"getTime", | |
"getDate", | |
"getHours", | |
"getMinutes", | |
"getSeconds", | |
"setDate", | |
"setHours", | |
"toString" | |
); | |
private final Date delegate; | |
public DateProxy(Date delegate) { | |
this.delegate = delegate; | |
} | |
public DateProxy(Instant delegate) { | |
this(Date.from(delegate)); | |
} | |
@Override | |
public Object getMember(String key) { | |
return switch (key) { | |
case "getTime" -> (ProxyExecutable) arguments -> delegate.getTime(); | |
case "getDate" -> (ProxyExecutable) arguments -> delegate.getDate(); | |
case "setHours" -> (ProxyExecutable) arguments -> { | |
delegate.setHours(arguments[0].asInt()); | |
return delegate.getTime(); | |
}; | |
case "setDate" -> (ProxyExecutable) arguments -> { | |
delegate.setDate(arguments[0].asInt()); | |
return delegate.getTime(); | |
}; | |
case "toString" -> (ProxyExecutable) arguments -> delegate.toString(); | |
default -> throw new UnsupportedOperationException("This date does not support: " + key); | |
}; | |
} | |
@Override | |
public Object getMemberKeys() { | |
return PROTOTYPE_FUNCTIONS.toArray(); | |
} | |
@Override | |
public boolean hasMember(String key) { | |
return PROTOTYPE_FUNCTIONS.contains(key); | |
} | |
@Override | |
public void putMember(String key, Value value) { | |
throw new UnsupportedOperationException("This date does not support adding new properties/functions."); | |
} | |
@Override | |
public Instant asInstant() { | |
return delegate.toInstant(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment