ebean-orm / ebean

Ebean ORM
https://ebean.io
Apache License 2.0
1.47k stars 260 forks source link

Whether DtoMeta.findproperty needs to add is prefix (handle dto queries where boolean property has "is" prefix) #1870

Closed weiwill closed 4 years ago

weiwill commented 4 years ago

1574649946592

like image

data class BasicCustomerDto(
    var code: String? = null,
    var name: String? = null,
    var phone: String? = null,
    var unionId: String? = null,
    var openId: String? = null,
    var wechatOpenId: String? = null,
    var wechatPhone: String? = null,
    var cusClass: String? = null,
    var member: Boolean = false,
//    var isMember: Boolean = false,
    var avatar: String? = null,
    var sex: String? = null
)
@Entity
@Table(name = "merchant_customer")
class MerchantCustomer: Model() {
    ...
    @Column(name = "is_member")
    var isMember: Boolean = false
    ...
}
    private final var cust = QMerchantCustomer._alias

    val basicSelectProperties =
        arrayOf(
            cust.code,
            cust.name,
            cust.phone,
            cust.openId,
            cust.wechatOpenId,
            cust.wechatPhone,
            cust.cusClass,
            cust.isMember,
            cust.avatar,
            cust.sex
        )
     QMerchantCustomer().code.eq(code).select(*basicSelectProperties)
            .asDto(BasicCustomerDto::class.java).findOne()
weiwill commented 4 years ago

Exception

com.sy.autodt.common.exception.GlobalExceptionHandler [31] -| javax.persistence.PersistenceException: Query threw SQLException:Unable to map DB column is_member to a property with a setter method on class com.sy.autodt.modules.customer.domain.dto.BasicCustomerDto Query was:select t0.code, t0.name, t0.phone, t0.open_id, t0.wechat_open_id, t0.wechat_phone, t0.cus_class, t0.is_member, t0.avatar, t0.sex from merchant_customer t0 where t0.code = ? at io.ebeaninternal.server.query.DtoQueryEngine.findList(DtoQueryEngine.java:32) at io.ebeaninternal.server.core.DtoQueryRequest.findList(DtoQueryRequest.java:101) at io.ebeaninternal.server.core.DefaultServer.findDtoOne(DefaultServer.java:1707) at io.ebeaninternal.server.querydefn.DefaultDtoQuery.findOne(DefaultDtoQuery.java:108) at com.sy.autodt.modules.customer.query.MerchantCustomerQuery.findDtoByCode(MerchantCustomerQuery.kt:44) at com.sy.autodt.modules.customer.service.CustomerService.findMerchantCustomerByCode(CustomerService.kt:38) at com.sy.autodt.modules.customer.controller.CustomerController.findByCode(CustomerController.kt:30) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1039) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897) at javax.servlet.http.HttpServlet.service(HttpServlet.java:645) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) at javax.servlet.http.HttpServlet.service(HttpServlet.java:750) at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74) at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129) at org.springframework.web.filter.AbstractRequestLoggingFilter.doFilterInternal(AbstractRequestLoggingFilter.java:262) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118) at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118) at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118) at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118) at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118) at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84) at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62) at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68) at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36) at io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68) at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:132) at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57) at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46) at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64) at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60) at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77) at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43) at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:269) at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:78) at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:133) at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:130) at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48) at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43) at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:249) at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:78) at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:99) at io.undertow.server.Connectors.executeRootHandler(Connectors.java:376) at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Caused by: java.lang.IllegalStateException: Unable to map DB column is_member to a property with a setter method on class com.sy.autodt.modules.customer.domain.dto.BasicCustomerDto at io.ebeaninternal.server.dto.DtoMeta.matchSetters(DtoMeta.java:113) at io.ebeaninternal.server.dto.DtoMeta.match(DtoMeta.java:65) at io.ebeaninternal.server.dto.DtoBeanDescriptor.buildPlan(DtoBeanDescriptor.java:36) at io.ebeaninternal.server.querydefn.DefaultDtoQuery.buildPlan(DefaultDtoQuery.java:83) at io.ebeaninternal.server.core.DtoQueryRequest.obtainPlan(DtoQueryRequest.java:79) at io.ebeaninternal.server.core.DtoQueryRequest.setResultSet(DtoQueryRequest.java:70) at io.ebeaninternal.server.core.DtoQueryRequest.executeSql(DtoQueryRequest.java:58) at io.ebeaninternal.server.query.DtoQueryEngine.findList(DtoQueryEngine.java:24) ... 74 more

weiwill commented 4 years ago

fix

    @get: JvmName("getIsMember")
    @set: JvmName("setIsMember")
    var isMember: Boolean = false
rbygrave commented 4 years ago

Testcase in Java:

DTO bean with boolean property without the is prefix: (eg. member)

  public static class ContactMemberDto {

    String lastName;
    boolean member;

   // getters and setters
}

Entity bean with a boolean property starting with is: (eg. isMember)

@Entity
@Cache(naturalKey = "email")
public class Contact {
  ...
  boolean isMember;

Query:

    final List<ContactMemberDto> contacts =
      DB.find(Contact.class).select("lastName, isMember")
      .asDto(ContactMemberDto.class)
      .findList();
javax.persistence.PersistenceException: Query threw SQLException:Unable to map DB column IS_MEMBER to a property with a setter method on class io.ebean.DtoQueryFromOrmTest$ContactMemberDto Query was:select t0.last_name, t0.is_member from contact t0

    at io.ebeaninternal.server.query.DtoQueryEngine.findList(DtoQueryEngine.java:32)
    at io.ebeaninternal.server.core.DtoQueryRequest.findList(DtoQueryRequest.java:101)
    at io.ebeaninternal.server.core.DefaultServer.findDtoList(DefaultServer.java:1743)
    at io.ebeaninternal.server.querydefn.DefaultDtoQuery.findList(DefaultDtoQuery.java:103)
    at io.ebean.DtoQueryFromOrmTest.toDto_withIsBooleanProperty(DtoQueryFromOrmTest.java:281)
rbygrave commented 4 years ago

Hi @weiwill thanks for this bug report, excellent work indeed. Very clear and easy to understand, well done.

Thanks, Rob.

weiwill commented 4 years ago

Thank you for your praise. It's my pleasure.

rbygrave commented 4 years ago

Note that this was logged as https://github.com/ebean-orm/ebean/issues/1870

On Mon, 25 Nov 2019 at 16:23, Wei notifications@github.com wrote:

fix

@get: JvmName("getIsMember")
@set: JvmName("setIsMember")
var isMember: Boolean = false

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/ebean-orm/ebean/issues/1870?email_source=notifications&email_token=AABTATM2MHNTLV7KMPLNRCLQVNALXA5CNFSM4JRCUH72YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEFA7HNI#issuecomment-557970357, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABTATPDISKKZ5XGAZYLX53QVNALXANCNFSM4JRCUH7Q .