jpa criteriabuilder和concat\u ws函数抛出nullpointerexception

pgccezyw  于 2021-07-11  发布在  Java
关注(0)|答案(1)|浏览(665)

我有以下用于过滤订单的标准查询。

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<OrderReducedDTO> cq = cb.createQuery(OrderReducedDTO.class);

Root<Order> root = cq.from(Order.class);
Join<Order, Customer> joinCustomer = root.join(Order_.customer);
Join<Order, Shipment> joinShipment = root.join(Order_.shipment);
Join<Shipment, Carrier> joinCarrier = joinShipment.join(Shipment_.carrier);
Join<Order, Payment> joinPayment = root.join(Order_.payment);
Join<Payment, PaymentMethod> joinPaymentMethod = joinPayment.join(Payment_.paymentMethod);
Join<Shipment, Country> joinCountry = joinShipment.join(Shipment_.country);

cq.select(cb.construct(
        OrderReducedDTO.class,
        root.get(Order_.id),
        root.get(Order_.incrementId),
        root.get(Order_.state),
        root.get(Order_.couponCode),
        root.get(Order_.totalDiscount),
        root.get(Order_.total),
        root.get(Order_.originChannel),
        root.get(Order_.branchOffice),
        joinCarrier.get(Carrier_.carrierCode),
        cb.function("CONCAT_WS", String.class,
                cb.literal(","),
                joinShipment.get(Shipment_.streetName),
                joinShipment.get(Shipment_.streetNumber),
                joinShipment.get(Shipment_.city),
                joinCountry.get(Country_.name),
                joinShipment.get(Shipment_.zipCode)
        ),
        joinPaymentMethod.get(PaymentMethod_.code),
        joinPayment.get(Payment_.paymentDate),
        root.get(Order_.createdAt),
        root.get(Order_.updatedAt),
        root.get(Order_.externalId),
        joinCustomer.get(Customer_.fullName)
));
... filters and predicates...

给我带来麻烦并导致npe被抛出的部分是

cb.function("CONCAT_WS", String.class,
                    cb.literal(","),
                    joinShipment.get(Shipment_.streetName),
                    joinShipment.get(Shipment_.streetNumber),
                    joinShipment.get(Shipment_.city),
                    joinCountry.get(Country_.name),
                    joinShipment.get(Shipment_.zipCode)
            )

更具体地说,当我使用 CONCAT_WS 功能。如果我使用 CONCAT ,它起作用了。这是我得到的线索:

java.lang.NullPointerException: null
at org.hibernate.hql.internal.NameGenerator.generateColumnNames(NameGenerator.java:27)
at org.hibernate.hql.internal.ast.util.SessionFactoryHelper.generateColumnNames(SessionFactoryHelper.java:434)
at org.hibernate.hql.internal.ast.tree.SelectClause.initializeColumnNames(SelectClause.java:270)
at org.hibernate.hql.internal.ast.tree.SelectClause.finishInitialization(SelectClause.java:260)
at org.hibernate.hql.internal.ast.tree.SelectClause.initializeExplicitSelectClause(SelectClause.java:255)
at org.hibernate.hql.internal.ast.HqlSqlWalker.useSelectClause(HqlSqlWalker.java:1026)
...

这是我的订单

@Getter
public class OrderReducedDTO {

    @JsonProperty("order_id")
    private Integer orderId;

    @JsonProperty("increment_id")
    private String incrementId;

    private OrderStates state;

    @JsonProperty("coupon_code")
    private String couponCode;

    @JsonProperty("total_discount")
    private BigDecimal totalDiscount;

    private BigDecimal total;

    @JsonProperty("origin_channel")
    private String originChannel;

    @JsonProperty("branch_office")
    private String branchOffice;

    @JsonProperty("shipping_method")
    private String shippingMethod;

    @JsonProperty("shipping_address")
    private String shippingAddress;

    @JsonProperty("payment_method")
    private String paymentMethod;

    @JsonProperty("payment_date")
    private Timestamp paymentDate;

    @JsonProperty("created_at")
    private Timestamp createdAt;

    @JsonProperty("updated_at")
    private Timestamp updatedAt;

    @JsonProperty("external_id")
    private String externalId;

    @JsonProperty("customer_full_name")
    private String customerFullName;

    @Setter
    private List<OrderProductReducedDTO> products;

    public OrderReducedDTO(Integer orderId,
                           String incrementId,
                           OrderStates state,
                           String couponCode,
                           BigDecimal totalDiscount,
                           BigDecimal total,
                           String originChannel,
                           String branchOffice,
                           String shippingMethod,
                           String shippingAddress,
                           String paymentMethod,
                           Object paymentDate,
                           Object createdAt,
                           Object updatedAt,
                           String externalId,
                           String customerFullName) {
        this.orderId = orderId;
        this.incrementId = incrementId;
        this.state = state;
        this.couponCode = couponCode;
        this.totalDiscount = totalDiscount;
        this.total = total;
        this.originChannel = originChannel;
        this.branchOffice = branchOffice;
        this.shippingMethod = shippingMethod;
        this.shippingAddress = shippingAddress;
        this.paymentMethod = paymentMethod;
        this.paymentDate = (Timestamp) paymentDate;
        this.createdAt = (Timestamp) createdAt; //https://hibernate.atlassian.net/browse/HHH-4179
        this.updatedAt = (Timestamp) updatedAt;
        this.externalId = externalId;
        this.customerFullName = customerFullName;
    }
}

我主要想知道的是我是否在使用 function 方法正确。我想我是因为 CONCAT 作品。

yxyvkwin

yxyvkwin1#

在hibernate中调试了几个小时后,我终于找到了问题的根源:
org/hibernate/hql/internal/ast/tree/constructornode.java

private Type[] resolveConstructorArgumentTypes() throws SemanticException {
    SelectExpression[] argumentExpressions = this.collectSelectExpressions();
    if (argumentExpressions == null) {
        return new Type[0];
    } else {
        Type[] types = new Type[argumentExpressions.length];

        for(int x = 0; x < argumentExpressions.length; ++x) {
            types[x] = argumentExpressions[x].getDataType();
        }

        return types;
    }
}
``` `argumentExpressions[x].getDataType()` 他回来了 `null` .
我在google上搜索发现,这可能是因为hibernate不知道给定sql函数的实际返回类型(显然它只知道最常见的返回类型)。然后,我按照这个答案实现了一个定制 `MetadataBuilderContributor` 像这样:

public class SqlFunctionsMetadataBuilderContributor implements MetadataBuilderContributor {

@Override
public void contribute(MetadataBuilder metadataBuilder) {
    metadataBuilder.applySqlFunction(
            "concat_ws",
            new StandardSQLFunction("concat_ws", StandardBasicTypes.STRING)
    );
}

}

在application.properties上,我添加了:

spring.jpa.properties.hibernate.metadata_builder_contributor=ar.com.glamit.glamitoms.config.hibernate.SqlFunctionsMetadataBuilderContributor

重新启动应用程序后, `argumentExpressions[x].getDataType()` 现在返回一个 `StringType` 以及 `NullPointerException` 他走了。

相关问题