Java Spring 数据 MongoDB 和 Java 8 次

Java Spring Data MongoDB and Java 8 Time

我正在尝试在我的 Java Spring 项目中使用 Java 8 LocalDate 和 LocalDateTime,但是我在保存和检索 Mongo 中的日期时遇到问题数据库

我正在使用 Spring 数据 Mongo (1.6.1.Release)。我已经按照 this answer 实现了自己的转换器(在它不起作用之后我尝试直接将 LocalDate 转换为 String)。

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

{ "_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):

数据库-config.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.access0(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.doWithPersistentProperty(MappingMongoConverter.java:278)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.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

好的,所以我想我可能有一些东西给你:)

您有 4 个转换器:

  • 本地日期 -> 字符串
  • 字符串 -> LocalDate
  • 本地日期时间 -> 字符串
  • 字符串 -> LocalDateTime

现在,查看您的 class 声明:

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 映射到字符串,而您的 class 名称表明您应该将 LocalDate 映射到字符串。

Copy/paste 有时是一种卑鄙和邪恶的东西。让我知道它是否有帮助!

Ps。您正在创建转换器两次:一次在数据库中-config.xml,而第二次通过 @Component 注释创建。