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

Maven打包Groovy为Jar后运行报错AbstractMethodError求助

Troubleshooting java.lang.AbstractMethodError with Groovy Jar

Hey there, let's break down why you're hitting this AbstractMethodError when using your Groovy-built Jar in another project. This error almost always boils down to a mismatch between how your Jar was compiled and how it's being run, so let's walk through the most likely causes and fixes.

The Problem Recap

You successfully built your Groovy code into a Jar using mvn package, imported it into another project, and it compiles fine—but when you actually call the Request class's ViewPoint method, you get an error pointing to pefservices.restapi.Request.getProperty(Ljava/lang/String;)Ljava/lang/Object;. The stack trace shows this happens when a closure inside ViewPoint tries to access the cache property.

Full Error Log

Exception in thread "main" java.util.concurrent.ExecutionException: java.lang.AbstractMethodError: pefservices.restapi.Request.getProperty(Ljava/lang/String;)Ljava/lang/Object;
at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1915)
at org.codehaus.groovy.vmplugin.v7.IndyInterface.selectMethod(IndyInterface.java:234)
at pefservices.restapi.Request.ViewPoint(Request.groovy:185)
at pefservices.restapi.Request.ViewPoint(Request.groovy)
at org.codehaus.groovy.vmplugin.v7.IndyInterface.selectMethod(IndyInterface.java:234)
at pefservices.restapi.Client.profile(Client.groovy:59)
at org.codehaus.groovy.vmplugin.v7.IndyInterface.selectMethod(IndyInterface.java:234)
at pefservices.restapi.Client.getName(Client.groovy:20)
at org.codehaus.groovy.vmplugin.v7.IndyInterface.selectMethod(IndyInterface.java:234)
at pefservices.viewpoint.Client.(Client.groovy:30)
at pefservices.viewpoint.Client.(Client.groovy)
at org.codehaus.groovy.vmplugin.v7.IndyInterface.selectMethod(IndyInterface.java:234)
at pefservices.viewpoint.User.(User.groovy:35)
at pefservices.viewpoint.User.(User.groovy)
at org.codehaus.groovy.vmplugin.v7.IndyInterface.selectMethod(IndyInterface.java:234)
at pefservices.setup.Session.enableFramework(Session.groovy:188)
at pefservices.setup.Session.enableFramework(Session.groovy)
at pefservices.setup.Session$enableFramework.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:115)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:135)
at main.App.main(App.groovy:15)
Caused by: java.lang.AbstractMethodError: pefservices.restapi.Request.getProperty(Ljava/lang/String;)Ljava/lang/Object;
at org.codehaus.groovy.runtime.InvokerHelper.getProperty(InvokerHelper.java:190)
at groovy.lang.Closure.getPropertyTryThese(Closure.java:313)
at groovy.lang.Closure.getPropertyOwnerFirst(Closure.java:307)
at groovy.lang.Closure.getProperty(Closure.java:296)
at org.codehaus.groovy.vmplugin.v7.IndyInterface.selectMethod(IndyInterface.java:234)
at pefservices.restapi.Request$_ViewPoint_closure1.doCall(Request.groovy:182)
at pefservices.restapi.Request$_ViewPoint_closure1.doCall(Request.groovy)
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.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:101)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:323)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:263)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1041)
at groovy.lang.Closure.call(Closure.java:405)
at org.codehaus.groovy.runtime.ConvertedClosure.invokeCustom(ConvertedClosure.java:50)
at org.codehaus.groovy.runtime.ConversionHandler.invoke(ConversionHandler.java:122)
at com.sun.proxy.$Proxy7.get(Unknown Source)
at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
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)

The Request Class Code

import java.nio.CharBuffer 
import java.util.concurrent.CompletableFuture 
import java.util.concurrent.Executors 
import java.util.concurrent.TimeUnit 
import groovy.json.JsonOutput 
import okhttp3.MediaType 
import okhttp3.MultipartBody 
import okhttp3.OkHttpClient 
import okhttp3.Request as Req 
import okhttp3.RequestBody 
import okhttp3.Response 
import okhttp3.OkHttpClient.Builder as ClientBuilder 
import okhttp3.Request.Builder 
import okio.Buffer 
import pefservices.restapi.User as UserAPI 
import pefservices.setup.* 

public class Request { 
    Map <String, String> cache = new HashMap <String, String>() 
    Map <String, CompletableFuture <?>> inProcess = new HashMap <String, CompletableFuture <?>>() 

    //includes Authorization 
    public def ViewPoint(String url, String RequestMethod, def requestBody='', Map headers=[:], boolean asAdmin=true, def asUser=null) { 
        if(!url.startsWith("http://")) { 
            url='http://'+url 
        } 
        String toBeCached = url+RequestMethod+requestBody+headers+Values+asAdmin+asUser 
        waitForRequestifExists(toBeCached) 
        if(!cache.containsKey(toBeCached)) { 
            def inputLine 
            inProcess.put(toBeCached, new CompletableFuture().supplyAsync( { 
                OkHttpClient client = new ClientBuilder().connectTimeout(120, TimeUnit.SECONDS).readTimeout(120, TimeUnit.SECONDS).build(); 
                println "restAPI [$RequestMethod] URL: "+url 
                Builder builder =new Builder().url(url) 
                // headers+=["Accept-Encoding" :"gzip, deflate"] 
                headers+=["Accept" :"application/json, text/plain, */*"] 
                headers+=["Accept-Language" :"en-US,en;q=0.5"] 
                headers+=["Expires" :"-1"] 
                headers+=["Connection" :"keep-alive"] 
                if(requestBody instanceof File) { 
                    String boundary = "-------------" + System.currentTimeMillis(); 
                    headers+=['Content-Type':'multipart/form-data; boundary='+boundary] 
                } 
                if(!headers.containsKey("Content-Type")) { 
                    headers+=["Content-Type" :"application/json; charset=UTF-8; odata.metadata=minimal"] 
                } 
                if (!url.contains("api/open") && url.contains(Session.url)) { 
                    if (asAdmin==true) { 
                        headers+=["Authorization" :Session.tokens['adminToken']]; 
                    } else if(asUser!=null) { 
                        UserAPI userAPI = new UserAPI(); 
                        headers+=["Authorization" :userAPI.loginPost(asUser).Token] 
                    } else{ 
                        headers+=["Authorization" :Session.tokens['userToken']]; 
                    } 
                } 
                for(entry in headers) { 
                    builder.addHeader(entry.key, entry.value) 
                } 
                if (!(requestBody instanceof String) && headers['Content-Type'].toString().contains("json")) { 
                    requestBody = JsonOutput.toJson(requestBody) 
                } 
                if (RequestMethod != 'GET') { 
                    try{ 
                        println "Json body:-&gt;"+ JsonOutput.prettyPrint(requestBody) 
                    } catch (Throwable ex) { 
                        println "body:"+ requestBody 
                    } 
                    if(requestBody instanceof File) { 
                        RequestBody body = RequestBody.create(MediaType.parse(headers['Content-Type']), requestBody) 
                        RequestBody formBody = new MultipartBody.Builder() 
                            .setType(MultipartBody.FORM) 
                            .addFormDataPart("file", requestBody.getName(), body) 
                            .build() 
                        builder.method(RequestMethod, formBody) 
                    } else{ 
                        RequestBody body = RequestBody.create(MediaType.parse(headers['Content-Type']), requestBody) 
                        builder.method(RequestMethod, body) 
                    } 
                } 
                Req request = builder.build() 
                Response response = client.newCall(request).execute() 
                int responseCode = response.code() 
                String responseTitle = response.message() 
                if(response.header("Content-Disposition")?.contains('attachment')) { 
                    String header =response.header("Content-Disposition") 
                    String fileExtension = header.substring(header.lastIndexOf('.')) 
                    println "Content-Disposition: attachment - File Extension -&gt;$fileExtension" 
                    File file = new File(".\TestFiles\temp$fileExtension") 
                    InputStream IS= response.body().byteStream() 
                    BufferedInputStream input = new BufferedInputStream(IS); 
                    OutputStream output = new FileOutputStream(file); 
                    byte[] data = new byte[1024]; 
                    long total = 0 
                    int count 
                    while ((count =input.read(data)) != -1) { 
                        total += count; 
                        output.write(data, 0, count); 
                    } 
                    output.flush(); 
                    output.close(); 
                    input.close(); 
                    inputLine = file 
                } else { 
                    inputLine = response.body().string() 
                } 
                println "RESTAPI Response Code: -&gt; " + responseCode 
                if (responseCode >= 400) { 
                    println "Message: -&gt; " + responseTitle 
                    println "Error Resposne body: -&gt; "+inputLine 
                    throw new Exception("Error Code =$responseCode URL: $url") 
                } 
                // 报错行 
                cache[toBeCached] = inputLine 
            }, new Executors().newSingleThreadExecutor())) 
            inProcess[toBeCached].get(120, TimeUnit.SECONDS) 
            inProcess.remove(toBeCached) 
            if(RequestMethod == "POST") {println "restapi.Request() -&gt;"+inputLine } 
            return inputLine 
        } else { 
            return cache.get(toBeCached) 
        } 
    } 

    public void waitForRequestifExists(String key) { 
        if(inProcess.containsKey(key)) { 
            this.inProcess[key].get(120, TimeUnit.SECONDS) 
        } 
    } 

    public void clearCache() { 
        this.cache = new HashMap <String, String>() 
        this.inProcess = new HashMap <String, CompletableFuture <?>>() 
    } 
}

Root Causes & Fixes

1. Mismatched Groovy Versions (Most Likely)

Groovy dynamically generates methods like getProperty for classes that implement GroovyObject (which all Groovy classes do by default). If you compiled your Jar with Groovy version X, but the project importing the Jar uses Groovy version Y, the method signatures might not line up—leading to this error when the runtime tries to call a method that doesn't exist in its version of Groovy.

Fix:

  • Check the pom.xml (or build.gradle) for both your Jar project and the importing project. Make sure the Groovy dependency version is identical in both. For example, if your Jar uses groovy-all:3.0.17, ensure the importing project doesn't use 3.0.18 or an older version like 2.5.21.

2. Incorrect Jar Packaging

If you used Maven's default Java compiler plugin to build your Groovy code instead of the Groovy Maven plugin, your Jar might not have the proper bytecode for Groovy's dynamic features. The Java compiler doesn't generate the GroovyObject interface methods that Groovy needs at runtime.

Fix:

  • Update your Jar project's pom.xml to use the groovy-maven-plugin for compilation. Here's a quick snippet:
    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.gmavenplus</groupId>
                <artifactId>gmavenplus-plugin</artifactId>
                <version>1.13.1</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>testCompile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    
  • Rebuild your Jar with this plugin—this ensures the bytecode includes all necessary Groovy runtime methods.

3. Closure Property Access Issues

The error happens inside the async closure in ViewPoint when it tries to access cache[toBeCached]. Groovy closures use getProperty under the hood to access outer class properties. If the closure's runtime environment doesn't have the right Groovy setup, this call fails.

Fix:

  • Explicitly reference the outer class instance in the closure to bypass the implicit getProperty call. Change the line:
    cache[toBeCached] = inputLine
    
    to:
    Request.this.cache[toBeCached] = inputLine
    
    This tells Groovy exactly where to find the cache property without relying on the dynamic getProperty method.

4. Class Loader Conflicts

In some cases, if the importing project uses multiple class loaders (like in Spring Boot or application servers), Groovy classes might be loaded twice—once by the Jar's class loader and once by the project's. This causes GroovyObject to be considered two different types, leading to method not found errors.

Fix:

  • Ensure Groovy dependencies are marked as compile or runtime (not provided) in both projects to avoid class loader mismatches.
  • If you're using Spring Boot, check that you're not including Groovy in both the Jar and the Boot project's dependencies—use dependencyManagement to align versions.

Next Steps

Start with checking Groovy versions first—it's the most common culprit. If that doesn't work, rebuild your Jar with the Groovy Maven plugin. If you still hit issues, try the explicit closure property reference.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 20:47:47