【问题标题】:Java Spring Data MongoDB and Java 8 TimeJava Spring Data MongoDB 和 Java 8 时间
【发布时间】:2015-01-17 20:26:30
【问题描述】:

我尝试在我的 Java Spring 项目中使用 Java 8 LocalDate 和 LocalDateTime,但我在保存和检索 MongoDB 中的日期时遇到问题。

我正在使用 Spring Data Mongo (1.6.1.Release)。我已经关注this answer 并实现了我自己的转换器(在它不起作用后我尝试直接将 LocalDate 转换为字符串)。

我猜的问题是 Spring Data 没有使用转换器,因为我的数据库条目如下所示:

{ "_id" : "frank@steiler.eu", "_class" : "de.steilerdev.myVerein.server.model.User", "firstName" : "Frank", "lastName" : "Steiler", "password" : "ef9aa46dd6f98af4878ed72eac69134ac236b5581e1207bd8e9d4f691ed20a48f4ed8d2b80229e4a649f1e7b5302c2c6166fc783b9cbfff6d8a18ad820652b1e", "salt" : "6b912cac277c6656", "memberSince" : { "year" : 2000, "month" : 1, "day" : 1 }, "birthday" : { "year" : 1994, "month" : 6, "day" : 28 } }

这是我的代码(如果我遗漏了什么,可以在here找到我的完整项目):

数据库配置.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans  xmlns="http://www.springframework.org/schema/data/mongo"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns:beans="http://www.springframework.org/schema/beans"
              xmlns:context="http://www.springframework.org/schema/context"
              xsi:schemaLocation=" http://www.springframework.org/schema/beans
                                   http://www.springframework.org/schema/beans/spring-beans.xsd
                                   http://www.springframework.org/schema/context
                                   http://www.springframework.org/schema/context/spring-context.xsd
                                   http://www.springframework.org/schema/data/mongo
                                   http://www.springframework.org/schema/data/mongo/spring-mongo.xsd">

        <!-- Including database configuration files -->
        <context:property-placeholder location="classpath:mongo.properties"/>

        <mapping-converter id="javaTimeConverter">
            <custom-converters>
                <converter>
                    <beans:bean class="de.steilerdev.myVerein.server.time.StringToLocalDateConverter" />
                </converter>
                <converter>
                    <beans:bean class="de.steilerdev.myVerein.server.time.StringToLocalDateTimeConverter" />
                </converter>
                <converter>
                    <beans:bean class="de.steilerdev.myVerein.server.time.LocalDateTimeToStringConverter" />
                </converter>
                <converter>
                    <beans:bean class="de.steilerdev.myVerein.server.time.LocalDateToStringConverter" />
                </converter>
            </custom-converters>
        </mapping-converter>

       <!-- Database configuration -->
       <repositories base-package="de.steilerdev.myVerein.server.model" />
       <template db-factory-ref="mongoDbFactory" converter-ref="javaTimeConverter"/>

       <db-factory host="${dbHost}"
                   port="${dbPort}"
                   dbname="${dbName}"
                   username="${dbUsername}"
                   password="${dbPassword}"/>

       <!-- Data Validation using Hibernate Validator and JavaX validation interface -->
       <beans:bean id="dataValidator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>

       <beans:bean id="mongoValidator" class="org.springframework.data.mongodb.core.mapping.event.ValidatingMongoEventListener">
              <beans:constructor-arg name="validator" ref="dataValidator"/>
       </beans:bean>

</beans:beans>

其中一个皈依者(其他人类似)

package de.steilerdev.myVerein.server.time;

import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

/**
 * This class is a converter used by SpringData, to convert a Java 8 LocalDateTime to a Java 7 Date
 */
@Component
public class LocalDateTimeToStringConverter implements Converter<LocalDateTime, String>
{
    @Override
    public String convert(LocalDateTime source) {
        return source == null ? null : source.toString();
    }
}

我的用户对象(没有 getter 和 setter)

package de.steilerdev.myVerein.server.model;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import de.steilerdev.myVerein.server.security.PasswordEncoder;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotBlank;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.keygen.KeyGenerators;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;

public class User implements UserDetails
{
    @NotBlank
    private String firstName;
    @NotBlank
    private String lastName;

    @Id
    @Indexed
    @NotBlank
    @Email
    private String email;

    @JsonIgnore
    @NotBlank
    private String password;

    @JsonIgnore
    @NotBlank
    private String salt;

    @JsonInclude(JsonInclude.Include.NON_NULL)
    private HashMap<String,String> privateInformation;
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private HashMap<String,String> publicInformation;

    @DBRef
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private List<Division> divisions;

    @JsonInclude(JsonInclude.Include.NON_NULL)
    private LocalDate memberSince;

    @JsonInclude(JsonInclude.Include.NON_NULL)
    private LocalDate passiveSince;

    @JsonInclude(JsonInclude.Include.NON_NULL)
    private LocalDate birthday;

    @Transient
    @JsonIgnore
    Collection<? extends GrantedAuthority> authorities;

    @Transient
    @JsonInclude(JsonInclude.Include.NON_NULL)
    boolean administrationAllowed;
}

我在登录时出现错误,如下:

org.springframework.security.authentication.InternalAuthenticationServiceException: No property null found on entity class java.time.LocalDate to bind constructor parameter to!
    at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:110)
    at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:132)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:156)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:177)
    at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:94)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:211)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:506)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:537)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1081)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:658)
    at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1566)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1523)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.data.mapping.model.MappingException: No property null found on entity class java.time.LocalDate to bind constructor parameter to!
    at org.springframework.data.mapping.model.PersistentEntityParameterValueProvider.getParameterValue(PersistentEntityParameterValueProvider.java:74)
    at org.springframework.data.mapping.model.SpELExpressionParameterValueProvider.getParameterValue(SpELExpressionParameterValueProvider.java:63)
    at org.springframework.data.convert.ReflectionEntityInstantiator.createInstance(ReflectionEntityInstantiator.java:71)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:249)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:230)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.readValue(MappingMongoConverter.java:1129)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.access$200(MappingMongoConverter.java:77)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter$MongoDbPropertyValueProvider.getPropertyValue(MappingMongoConverter.java:1078)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.getValueInternal(MappingMongoConverter.java:829)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter$1.doWithPersistentProperty(MappingMongoConverter.java:278)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter$1.doWithPersistentProperty(MappingMongoConverter.java:266)
    at org.springframework.data.mapping.model.BasicPersistentEntity.doWithProperties(BasicPersistentEntity.java:294)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:266)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:230)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:190)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:186)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:77)
    at org.springframework.data.mongodb.core.MongoTemplate$ReadDbObjectCallback.doWith(MongoTemplate.java:2121)
    at org.springframework.data.mongodb.core.MongoTemplate.executeFindOneInternal(MongoTemplate.java:1760)
    at org.springframework.data.mongodb.core.MongoTemplate.doFindOne(MongoTemplate.java:1577)
    at org.springframework.data.mongodb.core.MongoTemplate.findOne(MongoTemplate.java:497)
    at org.springframework.data.mongodb.repository.query.AbstractMongoQuery$SingleEntityExecution.execute(AbstractMongoQuery.java:307)
    at org.springframework.data.mongodb.repository.query.AbstractMongoQuery.execute(AbstractMongoQuery.java:107)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:421)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:381)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$DefaultMethodInvokingMethodInterceptor.invoke(RepositoryFactorySupport.java:512)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
    at com.sun.proxy.$Proxy1100.findByEmail(Unknown Source)
    at de.steilerdev.myVerein.server.security.UserAuthenticationService.loadUserByUsername(UserAuthenticationService.java:48)
    at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:102)
    ... 36 more

【问题讨论】:

    标签: java spring spring-mvc java-8 spring-data-mongodb


    【解决方案1】:

    好吧,我想我可能有一些东西要给你:)

    您有 4 个转换器:

    • Lo​​calDate -> 字符串
    • 字符串 -> 本地日期
    • Lo​​calDateTime -> 字符串
    • 字符串 -> 本地日期时间

    现在,看看你的类声明:

    public class LocalDateToStringConverter implements Converter<LocalDateTime, String>
    
    public class StringToLocalDateConverter implements Converter<String, LocalDate>
    
    public class LocalDateTimeToStringConverter implements Converter<LocalDateTime, String>
    
    public class StringToLocalDateTimeConverter implements Converter<String, LocalDateTime>
    

    第一个有什么问题?您将 LocalDateTime 映射到 String,而您的类名表明您应该将 LocalDate 映射到 String。

    复制/粘贴有时是一件卑鄙而邪恶的事情。让我知道它是否有帮助!

    附言。您正在创建您的转换器两次:一次在 database-config.xml 中,第二次通过 @Component 注释。

    【讨论】:

    • 嘿,谢谢你的回复,试过了,但没有改变任何行为。
    • @Fat_FS 我可以看到你已经添加了 github repo - 非常酷 :) 我会尝试调查它并让你知道。
    • 天哪,好球!这确实是问题所在。没有你就永远找不到它:)
    • 嗨,有什么问题吗?我也有类似的问题
    • @annesadleir 仔细阅读问题,然后阅读答案。当复制/粘贴代码和类名与实现的转换器接口类型不匹配时,OP 出错了。
    猜你喜欢
    • 2014-05-23
    • 2014-07-21
    • 1970-01-01
    • 2015-02-28
    • 2018-02-12
    • 1970-01-01
    • 2015-07-30
    • 2015-05-31
    • 1970-01-01
    相关资源
    最近更新 更多