Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't query for Instant #428

Closed
micheljung opened this issue Mar 9, 2017 · 7 comments
Closed

Can't query for Instant #428

micheljung opened this issue Mar 9, 2017 · 7 comments

Comments

@micheljung
Copy link

It seems like Elide doesn't properly convert String to Instant:
image

Filter was: endTime=="2017-03-15T23:00:00Z" (so it's RSQL)

Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to java.time.Instant
	at org.hibernate.type.descriptor.java.InstantJavaDescriptor.unwrap(InstantJavaDescriptor.java:26) ~[hibernate-java8-5.1.0.Final.jar:5.1.0.Final]
	at org.hibernate.type.descriptor.sql.TimestampTypeDescriptor$1.doBind(TimestampTypeDescriptor.java:48) ~[hibernate-core-5.1.0.Final.jar:5.1.0.Final]
	at org.hibernate.type.descriptor.sql.BasicBinder.bind(BasicBinder.java:74) ~[hibernate-core-5.1.0.Final.jar:5.1.0.Final]
	at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:253) ~[hibernate-core-5.1.0.Final.jar:5.1.0.Final]
	at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:248) ~[hibernate-core-5.1.0.Final.jar:5.1.0.Final]
	at org.hibernate.loader.Loader.bindPositionalParameters(Loader.java:2044) ~[hibernate-core-5.1.0.Final.jar:5.1.0.Final]
	at org.hibernate.loader.Loader.bindParameterValues(Loader.java:2013) ~[hibernate-core-5.1.0.Final.jar:5.1.0.Final]
	at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1943) ~[hibernate-core-5.1.0.Final.jar:5.1.0.Final]
	at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1896) ~[hibernate-core-5.1.0.Final.jar:5.1.0.Final]
	at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1874) ~[hibernate-core-5.1.0.Final.jar:5.1.0.Final]
	at org.hibernate.loader.Loader.scroll(Loader.java:2686) ~[hibernate-core-5.1.0.Final.jar:5.1.0.Final]
	at org.hibernate.loader.criteria.CriteriaLoader.scroll(CriteriaLoader.java:104) ~[hibernate-core-5.1.0.Final.jar:5.1.0.Final]
	at org.hibernate.internal.SessionImpl.scroll(SessionImpl.java:1740) ~[hibernate-core-5.1.0.Final.jar:5.1.0.Final]
	at org.hibernate.internal.CriteriaImpl.scroll(CriteriaImpl.java:377) ~[hibernate-core-5.1.0.Final.jar:5.1.0.Final]
	at com.yahoo.elide.datastores.hibernate5.HibernateTransaction.loadObjects(HibernateTransaction.java:271) ~[elide-datastore-hibernate5-2.5.1.jar:na]
	at com.yahoo.elide.datastores.hibernate5.HibernateTransaction.loadObjectsWithSortingAndPagination(HibernateTransaction.java:241) ~[elide-datastore-hibernate5-2.5.1.jar:na]
	at com.yahoo.elide.core.PersistentResource.loadRecordsWithSortingAndPagination(PersistentResource.java:352) ~[elide-core-2.5.1.jar:na]
	at com.yahoo.elide.parsers.state.CollectionTerminalState.getResourceCollection(CollectionTerminalState.java:135) ~[elide-core-2.5.1.jar:na]
	at com.yahoo.elide.parsers.state.CollectionTerminalState.handleGet(CollectionTerminalState.java:68) ~[elide-core-2.5.1.jar:na]
	at com.yahoo.elide.parsers.state.StateContext.handleGet(StateContext.java:110) ~[elide-core-2.5.1.jar:na]
	at com.yahoo.elide.parsers.GetVisitor.visitQuery(GetVisitor.java:34) ~[elide-core-2.5.1.jar:na]
	at com.yahoo.elide.parsers.GetVisitor.visitQuery(GetVisitor.java:21) ~[elide-core-2.5.1.jar:na]
	at com.yahoo.elide.generated.parsers.CoreParser$QueryContext.accept(CoreParser.java:556) ~[elide-core-2.5.1.jar:na]
	at org.antlr.v4.runtime.tree.AbstractParseTreeVisitor.visitChildren(AbstractParseTreeVisitor.java:70) ~[antlr4-runtime-4.5.1-1.jar:4.5.1-1]
	at com.yahoo.elide.generated.parsers.CoreBaseVisitor.visitStart(CoreBaseVisitor.java:20) ~[elide-core-2.5.1.jar:na]
	at com.yahoo.elide.parsers.BaseVisitor.visitStart(BaseVisitor.java:47) ~[elide-core-2.5.1.jar:na]
	at com.yahoo.elide.parsers.BaseVisitor.visitStart(BaseVisitor.java:33) ~[elide-core-2.5.1.jar:na]
	at com.yahoo.elide.generated.parsers.CoreParser$StartContext.accept(CoreParser.java:107) ~[elide-core-2.5.1.jar:na]
	at org.antlr.v4.runtime.tree.AbstractParseTreeVisitor.visit(AbstractParseTreeVisitor.java:42) ~[antlr4-runtime-4.5.1-1.jar:4.5.1-1]
	at com.yahoo.elide.Elide.get(Elide.java:369) ~[elide-core-2.5.1.jar:na]
	at com.yahoo.elide.Elide.get(Elide.java:407) ~[elide-core-2.5.1.jar:na]

Seems to be a similar problem like #384

Also, if you could add support for OffsetDateTime and LocalDateTime in the same run, that'd be awesome :-)

@clayreimann
Copy link
Contributor

Yeah, type conversion is a recurring issue.

I've put some thoughts together in #430 about how this might be tackled. My work there will be extended so that while a new Elide is being built you would have the option to add functions for coercing your own types.

@wcekan
Copy link
Contributor

wcekan commented Mar 10, 2017

You should be able to extend your Elide to support any custom conversions.
Register a custom Jackson serializer and a ConvertUtils converter.

public class MyElide extends Elide {
    public MyElide(ElideSettings elideSettings) {
        super(elideSettings);

        elideSettings.getMapper().getObjectMapper()
            .registerModule(new SimpleModule("instant", Version.unknownVersion())
            .addSerializer(java.time.Instant.class, new JsonSerializer<java.time.Instant>() {
                @Override
                public void serialize(java.time.Instant instant,
                                      JsonGenerator jsonGenerator,
                                      SerializerProvider serializerProvider)
                        throws IOException, JsonProcessingException {
                    if (instant == null) {
                        jsonGenerator.writeNull();
                    } else {
                        jsonGenerator.writeObject(instant.toString());
                    }
                }
            }));

        // initialize CoerceUtil, then register converter
        CoerceUtil.coerce("", String.class);
        ConvertUtils.register(new Converter() {
            @Override
            public <T> T convert(Class<T> type, Object value) {
                return (T) java.time.Instant.parse(String.valueOf(value));
            }
        }, java.time.Instant.class);
    }

@clayreimann
Copy link
Contributor

Hey @micheljung did you get a chance to look at @wcekan's suggestion? It would be interesting to know if it helped or not.

@micheljung
Copy link
Author

Hi @clayreimann not yet but it's still relevant and I'll soon have to implement it :) It may take a few more weeks but I'll keep you updated.

@micheljung
Copy link
Author

Hi,

So I finally came around to test this. I added:

    CoerceUtil.coerce("", String.class);
    ConvertUtils.register(new Converter() {
        @Override
        public <T> T convert(Class<T> type, Object value) {
            return (T) java.time.Instant.parse(String.valueOf(value));
        }
    }, java.time.Instant.class);

before creating new Elide and it worked! There was no reason to subclass Elide and I did not have to register a custom Jackson Module or serializer as I'm already including jackson-datatype-jsr310.

Still, would be good if Elide integrates it as well, I guess :) Thanks for your work, much appreciated!

@DennisMcWherter
Copy link
Collaborator

DennisMcWherter commented Aug 21, 2017

@micheljung glad to hear this worked! :)

I believe this isn't the default in Elide today because we thought it was sane to accept epoch values by default. However, maybe we could modify this module a bit and instead have something like this:

    ConvertUtils.register(new Converter() {
        @Override
        public <T> T convert(Class<T> type, Object value) {
            if (value instanceof Number) {
                return (T) java.time.Instant.ofEpochMilli(((Number) value).longValue());
            }
            return (T) java.time.Instant.parse(String.valueOf(value));
        }
    }, java.time.Instant.class);

Would something like that be reasonable @wcekan? I would have to test and ensure not all values come in as String.class of course :) but if it works the way I think it does, it seems like we could register a similar converter by default.

In any case, thanks for reporting back!

@aklish
Copy link
Member

aklish commented Dec 6, 2021

Resolved with Elide Serdes. Instead is supported.

@aklish aklish closed this as completed Dec 6, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants