You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hybris CronJob执行Groovy脚本遇方法重载歧义错误求助

解决Hybris CronJob中Groovy脚本的Transaction.execute方法重载歧义错误

问题描述

有一个用于根据多条件修改商品属性的Groovy脚本CronJob,去年第四季度运行正常,现在执行时触发方法重载歧义错误,错误信息如下:

Script execution has failed [reason: java.util.concurrent.ExecutionException: groovy.lang.GroovyRuntimeException: Ambiguous method overloading for method de.hybris.platform.tx.DefaultTransaction#execute.
Cannot resolve which method to invoke for [class UpdateWorker$_call_closure1] due to overlapping prototypes between:
    [interface de.hybris.platform.tx.TransactionBody]
    [interface de.hybris.platform.tx.TransactionBody$GenericTransactionBody]]

错误原因

de.hybris.platform.tx.DefaultTransaction类的execute方法存在两个重载版本,分别接收TransactionBody和TransactionBody$GenericTransactionBody接口参数。Groovy的闭包可以动态适配这两个接口的方法签名,导致JVM无法确定要调用哪个重载方法,从而触发歧义错误。这种情况通常是Hybris版本升级后新增了重载方法,或者Groovy类型推断逻辑变化导致的。

解决方案

方案1:显式指定闭包实现的接口

在调用execute方法时,将Groovy闭包强制转换为其中一个明确的接口(推荐TransactionBody),让JVM确定调用的方法。

修改UpdateWorker类中的call()方法里的Transaction.execute调用部分:

// 原代码
Transaction.current().execute(
    {
        lines.each { line ->
            // 原有逻辑...
        }
    }
)

// 修改后代码
Transaction.current().execute({
    lines.each { line ->
        // 原有逻辑保持不变...
    }
} as de.hybris.platform.tx.TransactionBody)

方案2:使用显式匿名内部类代替闭包

通过创建TransactionBody接口的匿名内部类实例,明确指定实现的接口,彻底避免重载歧义:

// 修改后的Transaction.execute调用
Transaction.current().execute(new de.hybris.platform.tx.TransactionBody() {
    @Override
    void execute() throws Exception {
        lines.each { line ->
            sessionService.executeInLocalViewWithParams(params, new SessionExecutionBody(){ 
                public void executeWithoutResult(){
                    // 原有内部逻辑完全保留...
                }
            })
        }
    }
})

完整修改后的UpdateWorker.call()方法示例

def String call() {
    def startThread = new Date()
    privateLogger.info('IsNested transaction: ' + Transaction.current().isNested())
    // 使用方案1的修改方式
    Transaction.current().execute({
        lines.each { line ->
            sessionService.executeInLocalViewWithParams(params, new SessionExecutionBody(){ public void executeWithoutResult(){
                    def queryForSubstitution = /select distinct {s.pk} from {Substitution as s} where ({s.partForSubstitutionCode} = ?productPk or {s.skuReplacementCode} = ?productPk) and {s.partForSubstitutionCode} is not null and {s.skuReplacementCode} is not null/
                    def productPk = line.getCode();
                    def queryParams = [:];
                    queryParams.put('productPk', productPk);
                    final FlexibleSearchQuery fsQuery = new FlexibleSearchQuery(queryForSubstitution, queryParams);
                    
                    def substitutions = flexibleSearchService.search(fsQuery).getResult();
                    
                    if(substitutions.size() == 0)
                    {
                        line.setSubstitutionCode(subCodeNoEntry);
                        line.setSubstitutionIndicator(subIndicatorEmpty);
                    }
                    else{
                        def subFromList = [];
                        def subToList = [];
                        //Split into 2 list
                        for(SubstitutionModel substitution : substitutions)
                        {
                            //These fields are mandatories during hotfolder process
                            //Anyway are not mandatories in hybris sistem, this null check avoid to abort cronjob
                            if(substitution.getPartForSubstitutionCode() != null && substitution.getSkuReplacementCode() != null)
                            {
                                if(substitution.getPartForSubstitutionCode() == productPk) {
                                    subFromList.add(substitution)
                                } else {
                                    subToList.add(substitution)
                                }
                            }
                        }
                        //Calculate substitution code
                        def substitutionCode;
                    
                        if(subFromList.size() == 0){
                            substitutionCode = subCodeNoEntry
                        }
                        else if(subFromList.size() == 1){
                            if(subFromList.get(0).getConditionalNotes() != null && !subFromList.get(0).getConditionalNotes().isEmpty())
                            {
                                substitutionCode = subCodeMoreEntriesWithConditionalNotes
                            }   
                            else{
                                substitutionCode = subCodeOneEntry
                            }   
                        }
                        else{
                            substitutionCode = subCodeMoreEntriesNoConditionalNotes
                            for(SubstitutionModel substitution : substitutions)
                            {
                                if(substitution.getConditionalNotes() != null && !substitution.getConditionalNotes().isEmpty()){
                                    substitutionCode = subCodeMoreEntriesWithConditionalNotes
                                    break
                                }
                            }               
                        }
                        line.setSubstitutionCode(substitutionCode)
                        
                        //Calculate substitution indicator
                        def substitutionIndicator;
                    
                        if(subFromList.size() > 0 && subToList.size() > 0){
                            substitutionIndicator = subIndicatorBoth
                        }
                        else if (subFromList.size() > 0 && subToList.size() == 0){
                            substitutionIndicator = subIndicatorForward
                        }
                        else if (subFromList.size() == 0 && subToList.size() > 0){
                            substitutionIndicator = subIndicatorPrevious
                        }
                        line.setSubstitutionIndicator(substitutionIndicator) 
                    }   
                    line.setTriggerSubstitutionCronjob(false)
                    modelService.save(line)                         
                                    
            }})
        }
    } as de.hybris.platform.tx.TransactionBody)
    def stopThread = new Date()
    def TimeDuration td = TimeCategory.minus( stopThread, startThread )
    privateLogger.info('Sanitized ' + lines.size() + ' elements in' + td)
    return 'Sanitized ' + lines.size() + ' elements in' + td
}

内容的提问来源于stack exchange,提问作者iamrooovic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 10:25:07