Giter Site home page Giter Site logo

dromara / forest Goto Github PK

View Code? Open in Web Editor NEW
1.6K 31.0 204.0 8.02 MB

A high-level and lightweight declarative HTTP client framework for Java. it makes sending HTTP requests in Java easier.

License: MIT License

Java 99.71% HTML 0.04% Kotlin 0.25%
declarative-http-client http http-client https rest restful socks java-http-client request fegin

forest's People

Contributors

bryan31 avatar chming7 avatar codingox avatar dependabot[bot] avatar designer-framework avatar fangzhengjin avatar houkunlin avatar idevmo avatar leesonwei avatar mchgood avatar microsiland avatar mysinglelive avatar noear avatar sanjeever avatar shanyepifu avatar stray-developer avatar tanglinyan avatar witt-bit avatar xpblog avatar yakax avatar yangle94 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

forest's Issues

forest-spring-boot-starter version:1.5.0 url param not encode.

使用forest-spring-boot-starter执行HTTP请求时,默认backend为okhttp3。
debug发现并未对Query参数进行URL Encode,
调用链路
com.dtflys.forest.backend.okhttp3.executor.AbstractOkHttp3Executor#execute(com.dtflys.forest.handler.LifeCycleHandler, int)
com.dtflys.forest.backend.url.SimpleURLBuilder#buildUrl

backend修改为httpclient调用的com.dtflys.forest.backend.url.QueryableURLBuilder则进行了正常URL Encode。
image
image

请修复

AsyncHttpExecutor的pool希望能够配置

com.dtflys.forest.backend.AsyncHttpExecutor当前是硬编码SynchronousQueue

        pool = new ThreadPoolExecutor(
                coreSize, maxAsyncThreadSize != null ? maxAsyncThreadSize : DEFAULT_MAX_THREAD_SIZE,
                3, TimeUnit.MINUTES,
                new SynchronousQueue<>(),
                tf -> {
                    Thread thread = new Thread(tf, "forest-async-" + threadCount.getAndIncrement());
                    thread.setDaemon(true);
                    return thread;
                }, new AsyncAbortPolicy());

我希望使用LinkedBlockingQueue希望能给一个配置选项

在普通项目中使用post请求会报错

package com.example.request;

import com.dtflys.forest.annotation.Body;
import com.dtflys.forest.annotation.Get;
import com.dtflys.forest.annotation.Post;


public interface Client {
    @Post(url = "http://127.0.0.1:8090/api/admin/login/precheck", contentType = "application/json")
    public String login(@Body("username") String username, @Body("password") String password);
}
package com.example;

import com.dtflys.forest.config.ForestConfiguration;
import com.example.request.Client;

public class main {
    public static void main(String[] args) {
        Client myClient = ForestConfiguration.configuration().createInstance(Client.class);
        myClient.login("[email protected]", "123456789");
    }
}

运行报错:

[main] INFO com.dtflys.forest.config.ForestConfiguration - [Forest] Http Backend: okhttp3
Exception in thread "main" java.lang.NullPointerException
	at com.dtflys.forest.backend.body.AbstractBodyBuilder.buildBody(AbstractBodyBuilder.java:151)
	at com.dtflys.forest.backend.okhttp3.executor.AbstractOkHttp3Executor.prepareBody(AbstractOkHttp3Executor.java:171)
	at com.dtflys.forest.backend.okhttp3.executor.AbstractOkHttp3Executor.execute(AbstractOkHttp3Executor.java:181)
	at com.dtflys.forest.backend.okhttp3.executor.AbstractOkHttp3Executor.execute(AbstractOkHttp3Executor.java:281)
	at com.dtflys.forest.http.ForestRequest.execute(ForestRequest.java:1608)
	at com.dtflys.forest.http.ForestRequest.execute(ForestRequest.java:1625)
	at com.dtflys.forest.reflection.ForestMethod.invoke(ForestMethod.java:1143)
	at com.dtflys.forest.proxy.InterfaceProxyHandler.invoke(InterfaceProxyHandler.java:121)
	at com.sun.proxy.$Proxy9.login(Unknown Source)
	at com.example.main.main(main.java:16)

求助大佬 在本地运行forest 编译报错

Error creating bean with name 'helloworld': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'amap': FactoryBean threw exception on object creation; nested exception is com.dtflys.forest.exceptions.ForestRuntimeException: java.lang.NoSuchMethodException: java.lang.invoke.MethodHandles$Lookup.<init>(java.lang.Class,int)

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>demo</description>
    <properties>
        <java.version>11</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-resolver-dns-native-macos</artifactId>
            <scope>runtime</scope>
            <classifier>osx-x86_64</classifier>
            <version>4.1.59.Final</version>
        </dependency>
        <dependency>
            <groupId>org.java-websocket</groupId>
            <artifactId>Java-WebSocket</artifactId>
            <version>1.3.8</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.56</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <!-- 对象池,使用redis时必须引入 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

        <!--        <dependency>-->
        <!--            <groupId>org.springframework.boot</groupId>-->
        <!--            <artifactId>spring-boot-starter-data-redis-reactive</artifactId>-->
        <!--        </dependency>-->
<!--        <dependency>-->
<!--            <groupId>org.springframework.boot</groupId>-->
<!--            <artifactId>spring-boot-starter-quartz</artifactId>-->
<!--        </dependency>-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>com.dtflys.forest</groupId>
            <artifactId>forest-spring-boot-starter</artifactId>
            <version>1.5.8</version>
        </dependency>
        <!--        <dependency>-->
        <!--            <groupId>org.mybatis.spring.boot</groupId>-->
        <!--            <artifactId>mybatis-spring-boot-starter</artifactId>-->
        <!--            <version>2.2.0</version>-->
        <!--        </dependency>-->
<!--        <dependency>-->
<!--            <groupId>com.dtflys.forest</groupId>-->
<!--            <artifactId>forest-spring-boot-starter</artifactId>-->
<!--            <version>1.5.14</version>-->
<!--        </dependency>-->
<!--        <dependency>-->
<!--            <groupId>org.springframework.boot</groupId>-->
<!--            <artifactId>spring-boot-devtools</artifactId>-->
<!--            <scope>runtime</scope>-->
<!--            <optional>true</optional>-->
<!--        </dependency>-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

代码

Ammp.java 
package com.example.demo.client;

import com.dtflys.forest.annotation.BaseRequest;
import com.dtflys.forest.annotation.Query;
import com.dtflys.forest.annotation.Request;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
 * 高德地图服务客户端接口
 *
 * @author gongjun
 */
@BaseRequest(baseURL = "http://ditu.amap.com")
@Component
public interface Amap {

    /**
     * 根据经纬度获取详细地址
     *
     * @param longitude 经度
     * @param latitude  纬度
     * @return
     */
    @Request(url = "/service/regeo")
    Map getLocation(@Query("longitude") String longitude, @Query("latitude") String latitude);

}


Helloworld (controller)
package com.example.demo.controller;

import com.example.demo.client.Amap;
import com.example.demo.service.userService;
import com.example.demo.task.AsyncTask;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.Map;

@RestController
public class Helloworld {
    @Resource
    protected AsyncTask asyncTask;
    @Resource
    protected userService UserService;
    @Resource
    private Amap amap;

 
    @RequestMapping("/httpclient")
    public String httpclient() {
        Map result = amap.getLocation("121.475078", "31.223577");
        System.out.println(result);
        return "444";
    }

}

main

package com.example.demo;

import com.dtflys.forest.springboot.annotation.ForestScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.scheduling.annotation.EnableAsync;

@EnableAsync
@EnableCaching
@SpringBootApplication
@ForestScan(basePackages = "com.example.demo.client")
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
//        ApplicationContext ctx = SpringApplication.run(DemoApplication.class, args);
//        String[] beanNames = ctx.getBeanDefinitionNames();
//        Arrays.sort(beanNames);
//        for (String beanName : beanNames) {
//            System.out.println(beanName);
//        }
    }

}


URL QueryString 参数问题

URL查询参数在有些特殊的网站无法生效,并且会有查询参数丢失的问题。

具体表现如下:
/template/file/?${name} 会导致 ${name} 参数值丢失,实际只请求了 /template/file/ 地址,导致请求结果不正确。

经过个人断点调试,解决该问题的大致范围在 QueryableURLBuilder.java 的第32-34行,以及 MappingTemplate.java 的第364-366行

不支持jdk17

springboot jdk17环境启动报错

Caused by: com.dtflys.forest.exceptions.ForestRuntimeException: java.lang.NoSuchMethodException: java.lang.invoke.MethodHandles$Lookup.(java.lang.Class,int)
at com.dtflys.forest.proxy.InterfaceProxyHandler.(InterfaceProxyHandler.java:69) ~[forest-core-1.5.19.jar:?]
at com.dtflys.forest.proxy.ProxyFactory.createInstance(ProxyFactory.java:42) ~[forest-core-1.5.19.jar:?]
at com.dtflys.forest.config.ForestConfiguration.createInstance(ForestConfiguration.java:1521) ~[forest-core-1.5.19.jar:?]
at com.dtflys.forest.Forest.client(Forest.java:56) ~[forest-core-1.5.19.jar:?]

自定义注解优化建议

当使用自定义注解时,注解变量的值引用Forest全局变量进行赋值,当全局变量定义不存在时,
会报空指针异常。此处建议优化为,当全局变量的引用值为空时,使用自定义注解的对应字段的默认值,
没有默认值时再抛异常。
举例如下:

public @interface ForestPorxy {
String isProxy() default "false";
}
@GETrequest(url = "https:.//www.baidu.com")
@ForestPorxy(isProxy = "${proxy.baidui}")
ForestResponse evtBaidu();

如果proxy.baidui 在配置文件中不存在,现在的版本为直接抛出异常,且不会进入自定义注解的生命周期。

Dependency org.apache.httpcomponents:httpclient, leading to CVE problem

Hi, In forest-master/forest-core,there is a dependency org.apache.httpcomponents:httpclient:4.5.2 that calls the risk method.

CVE-2020-13956

The scope of this CVE affected version is [,4.5.13)

After further analysis, in this project, the main Api called is <org.apache.http.client.utils.URIUtils: org.apache.http.HttpHost extractHost(java.net.URI)>

Risk method repair link : GitHub

CVE Bug Invocation Path--

Path Length : 4

<org.apache.http.client.utils.URIUtils: org.apache.http.HttpHost extractHost(java.net.URI)>
at <org.apache.http.impl.client.DecompressingHttpClient: org.apache.http.HttpHost getHttpHost(org.apache.http.client.methods.HttpUriRequest)> (org.apache.http.impl.client.DecompressingHttpClient.java:[137]) in /.m2/repository/org/apache/httpcomponents/httpclient/4.5.2/httpclient-4.5.2.jar
at <org.apache.http.impl.client.DecompressingHttpClient: org.apache.http.HttpResponse execute(org.apache.http.client.methods.HttpUriRequest)> (org.apache.http.impl.client.DecompressingHttpClient.java:[123]) in /.m2/repository/org/apache/httpcomponents/httpclient/4.5.2/httpclient-4.5.2.jar
at <com.dtflys.forest.backend.httpclient.request.SyncHttpclientRequestSender: void sendRequest(com.dtflys.forest.http.ForestRequest,com.dtflys.forest.backend.httpclient.response.HttpclientResponseHandler,org.apache.http.client.methods.HttpUriRequest,com.dtflys.forest.handler.LifeCycleHandler,org.apache.http.client.CookieStore,java.util.Date,int)> (com.dtflys.forest.backend.httpclient.request.SyncHttpclientRequestSender.java:[98]) in /detect/unzip/forest-master/forest-core/target/classes

Dependency tree--

[INFO] com.dtflys.forest:forest-core:jar:1.5.2-BETA
[INFO] +- com.googlecode.juniversalchardet:juniversalchardet:jar:1.0.3:compile
[INFO] +- org.apache.httpcomponents:httpclient:jar:4.5.2:compile
[INFO] |  \- commons-codec:commons-codec:jar:1.13:compile
[INFO] +- org.apache.httpcomponents:httpclient-cache:jar:4.5.2:compile
[INFO] +- org.apache.httpcomponents:httpcore:jar:4.4.5:compile
[INFO] +- org.apache.httpcomponents:httpmime:jar:4.5.2:compile
[INFO] +- org.apache.httpcomponents:httpcore-nio:jar:4.4.5:compile
[INFO] +- org.apache.httpcomponents:httpasyncclient:jar:4.1.2:compile
[INFO] +- com.squareup.okhttp3:okhttp:jar:3.14.9:compile
[INFO] |  \- com.squareup.okio:okio:jar:1.17.2:compile
[INFO] +- com.google.code.findbugs:jsr305:jar:3.0.1:compile
[INFO] +- commons-io:commons-io:jar:2.4:compile
[INFO] +- com.alibaba:fastjson:jar:1.2.48:provided
[INFO] +- com.fasterxml.jackson.core:jackson-core:jar:2.9.10:provided
[INFO] +- com.fasterxml.jackson.core:jackson-databind:jar:2.9.10.7:provided
[INFO] +- com.fasterxml.jackson.core:jackson-annotations:jar:2.9.10:provided
[INFO] +- com.google.code.gson:gson:jar:1.7.1:provided
[INFO] +- commons-logging:commons-logging:jar:1.1:compile
[INFO] |  +- log4j:log4j:jar:1.2.12:compile
[INFO] |  +- logkit:logkit:jar:1.0.1:compile
[INFO] |  \- avalon-framework:avalon-framework:jar:4.1.3:compile
[INFO] +- org.slf4j:slf4j-api:jar:1.7.10:compile
[INFO] +- xerces:xercesImpl:jar:2.12.0:provided
[INFO] |  \- xml-apis:xml-apis:jar:1.4.01:provided
[INFO] +- org.mock-server:mockserver-netty:jar:3.10.4:provided
[INFO] |  +- org.mock-server:mockserver-client-java:jar:3.10.4:provided
[INFO] |  |  \- org.apache.commons:commons-lang3:jar:3.9:provided
[INFO] |  +- org.mock-server:mockserver-core:jar:3.10.4:provided
[INFO] |  |  +- javax.servlet:javax.servlet-api:jar:4.0.1:provided
[INFO] |  |  +- com.twitter:finagle-native_2.11:jar:6.33.0:provided
[INFO] |  |  |  +- org.scala-lang:scala-library:jar:2.11.7:provided
[INFO] |  |  |  +- com.twitter:finagle-core_2.11:jar:6.33.0:provided
[INFO] |  |  |  |  +- com.twitter:util-app_2.11:jar:6.32.0:provided
[INFO] |  |  |  |  +- com.twitter:util-cache_2.11:jar:6.32.0:provided
[INFO] |  |  |  |  +- com.twitter:util-codec_2.11:jar:6.32.0:provided
[INFO] |  |  |  |  +- com.twitter:util-collection_2.11:jar:6.32.0:provided
[INFO] |  |  |  |  |  +- javax.inject:javax.inject:jar:1:provided
[INFO] |  |  |  |  |  \- commons-collections:commons-collections:jar:3.2.1:provided
[INFO] |  |  |  |  +- com.twitter:util-core_2.11:jar:6.32.0:provided
[INFO] |  |  |  |  |  +- com.twitter:util-function_2.11:jar:6.32.0:provided
[INFO] |  |  |  |  |  \- org.scala-lang.modules:scala-parser-combinators_2.11:jar:1.0.4:provided
[INFO] |  |  |  |  +- com.twitter:util-hashing_2.11:jar:6.32.0:provided
[INFO] |  |  |  |  +- com.twitter:util-jvm_2.11:jar:6.32.0:provided
[INFO] |  |  |  |  +- com.twitter:util-lint_2.11:jar:6.32.0:provided
[INFO] |  |  |  |  +- com.twitter:util-logging_2.11:jar:6.32.0:provided
[INFO] |  |  |  |  +- com.twitter:util-registry_2.11:jar:6.32.0:provided
[INFO] |  |  |  |  +- com.twitter:util-stats_2.11:jar:6.32.0:provided
[INFO] |  |  |  |  +- com.twitter:jsr166e:jar:1.0.0:provided
[INFO] |  |  |  |  \- io.netty:netty:jar:3.10.1.Final:provided
[INFO] |  |  |  \- com.twitter:finagle-http_2.11:jar:6.33.0:provided
[INFO] |  |  |     \- commons-lang:commons-lang:jar:2.6:provided
[INFO] |  |  +- com.jcraft:jzlib:jar:1.1.3:provided
[INFO] |  |  +- org.bouncycastle:bcmail-jdk15on:jar:1.52:provided
[INFO] |  |  +- org.bouncycastle:bcpkix-jdk15on:jar:1.52:provided
[INFO] |  |  +- org.skyscreamer:jsonassert:jar:1.5.0:provided
[INFO] |  |  |  \- com.vaadin.external.google:android-json:jar:0.0.20131108.vaadin1:provided
[INFO] |  |  \- com.github.fge:json-schema-validator:jar:2.2.6:provided
[INFO] |  |     +- joda-time:joda-time:jar:2.10.5:provided
[INFO] |  |     +- com.googlecode.libphonenumber:libphonenumber:jar:6.2:provided
[INFO] |  |     +- com.github.fge:json-schema-core:jar:1.2.5:provided
[INFO] |  |     |  +- com.github.fge:uri-template:jar:0.9:provided
[INFO] |  |     |  |  \- com.github.fge:msg-simple:jar:1.1:provided
[INFO] |  |     |  |     \- com.github.fge:btf:jar:1.2:provided
[INFO] |  |     |  +- com.github.fge:jackson-coreutils:jar:1.8:provided
[INFO] |  |     |  \- org.mozilla:rhino:jar:1.7R4:provided
[INFO] |  |     +- javax.mail:mailapi:jar:1.4.3:provided
[INFO] |  |     |  \- javax.activation:activation:jar:1.1:provided
[INFO] |  |     \- net.sf.jopt-simple:jopt-simple:jar:4.6:provided
[INFO] |  +- org.bouncycastle:bcprov-jdk15on:jar:1.52:provided
[INFO] |  +- com.google.guava:guava:jar:18.0:provided
[INFO] |  +- ch.qos.logback:logback-classic:jar:1.2.3:provided
[INFO] |  |  \- ch.qos.logback:logback-core:jar:1.2.3:provided
[INFO] |  +- janino:janino:jar:2.5.10:provided
[INFO] |  \- org.mock-server:mockserver-logging:jar:3.10.4:provided

Suggested solutions:

Update dependency version to 4.5.13 or higher

Thank you very much.

@OAuth2 注解可配置化

场景

项目是spring boot,@OAuth2 中的的配置信息需要做到配置化,如果再代码中硬编码灵活性太差。于是想通过forest变量来解决,如下

@OAuth2(
    tokenUri = "${testaouth2.tokenUri}",
    clientId = "${testaouth2.clientId}",
    clientSecret = "${testaouth2.clientSecret}",
    grantType = OAuth2.GrantType.PASSWORD,
    scope = "${testaouth2.scope}",
    username = "${testaouth2.username}"
    password = "${testaouth2.password}"
)

问题

grantType 是一个枚举,如何做到外部传参呢?

SSL模块是否可以开放接口支持外部配置?

  1. keyStore口令仅支持明文配置
  2. 证书校验的TrustStrategy目前不支持自定义,仅有TrustSelfSignedStrategy()或new TrustAllManager()
  3. ForestSSLConnectionFactory中hostnameVerifier不支持外部定义

ForestJacksonConverter 可否支持一下自定义配置

ForestJacksonConverter 可否支持一下自定义配置,比如 下划线 转驼峰支持 一些 api 接口 返回数据是 下划线格式的字段,需要自动映射为 驼峰格式,需要

 mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);

关于get请求中,@Query实体类里的List问题

我有一个dto实体类Entity{ String a,int b,List c },在get请求中他被@query修饰作为url上的参数,如下getReuest(@query Entity e),但是实际拼出来的url是http://xxxxx?a=xx&b=xx&c=[\"xxx\",\“xxxx\”],他把我的list序列化了,然后我试着把List c单独拿出来,并把Entity修改为{ String a,int b},而c作为第二个参数如下getReuest(@query Entity e,@query("c") List c),拼出来的url是http://xxxxx?a=xx&b=xx&c=xxx&c=xxxx,这是否是一个缺陷?

拦截器中出现异常时如何自定义返回值问题

当调用接口失败时,方法的返回值通常是null,例如方法:
@request(url = "${0}",
interceptor = {VerifyInvoiceInterceptor.class},
type = "post",
contentType = "application/json",
dataType = "json")
VerifyInvoiceResponse verifyInvoice(String url, @dataobject VerifyInvoiceDTO verifyInvoiceDTO);
如果方法调用异常,返回值verifyInvoiceResponse是null,是否可通过拦截器重新自定义返回值,使得verifyInvoiceResponse 不为null

拦截器-onSuccess失效

使用forest拦截器,请求成功,有数据和200响应体状态码返回,但是却没有进入拦截器的onSuccess方法

Error creating bean with name 'getForestBeanRegister'

Hi, Thank you for making such an excellent framework.

Now my new project still chose forest.

But now I have encountered some mistakes and need your help. As the title indicates.

My development environment:

  1. Spring boot 3.0.0-m1
  2. OpenJDK 17

There are detailed error logs here:

2022-03-08 13:51:14.848  INFO 2345 --- [           main] c.a.***.Application       : Starting Application using Java 17.0.2 on ***-Mac.local with PID 2345 (/Users/loadClass/IdeaProjects/target/classes started by *** in /Users/***/IdeaProjects/***)
2022-03-08 13:51:14.849  INFO 2345 --- [           main] c.a.***.Application       : No active profile set, falling back to default profiles: default
2022-03-08 13:51:15.207  WARN 2345 --- [           main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'getForestBeanRegister' defined in class path resource [com/dtflys/forest/springboot/ForestAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.dtflys.forest.springboot.ForestBeanRegister]: Factory method 'getForestBeanRegister' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'forestConfiguration': Bean instantiation via factory method failed; nested exception is java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException
2022-03-08 13:51:15.220  INFO 2345 --- [           main] ConditionEvaluationReportLoggingListener : 

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2022-03-08 13:51:15.232 ERROR 2345 --- [           main] o.s.boot.SpringApplication               : Application run failed

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'getForestBeanRegister' defined in class path resource [com/dtflys/forest/springboot/ForestAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.dtflys.forest.springboot.ForestBeanRegister]: Factory method 'getForestBeanRegister' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'forestConfiguration': Bean instantiation via factory method failed; nested exception is java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException
	at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:634) ~[spring-beans-6.0.0-M2.jar:6.0.0-M2]
	at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:622) ~[spring-beans-6.0.0-M2.jar:6.0.0-M2]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1310) ~[spring-beans-6.0.0-M2.jar:6.0.0-M2]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1161) ~[spring-beans-6.0.0-M2.jar:6.0.0-M2]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:566) ~[spring-beans-6.0.0-M2.jar:6.0.0-M2]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:526) ~[spring-beans-6.0.0-M2.jar:6.0.0-M2]
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[spring-beans-6.0.0-M2.jar:6.0.0-M2]
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.0.0-M2.jar:6.0.0-M2]
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[spring-beans-6.0.0-M2.jar:6.0.0-M2]
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) ~[spring-beans-6.0.0-M2.jar:6.0.0-M2]
	at org.springframework.context.support.PostProcessorRegistrationDelegate.registerBeanPostProcessors(PostProcessorRegistrationDelegate.java:266) ~[spring-context-6.0.0-M2.jar:6.0.0-M2]
	at org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(AbstractApplicationContext.java:762) ~[spring-context-6.0.0-M2.jar:6.0.0-M2]
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:567) ~[spring-context-6.0.0-M2.jar:6.0.0-M2]
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145) ~[spring-boot-3.0.0-M1.jar:3.0.0-M1]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:719) ~[spring-boot-3.0.0-M1.jar:3.0.0-M1]
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:401) ~[spring-boot-3.0.0-M1.jar:3.0.0-M1]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:302) ~[spring-boot-3.0.0-M1.jar:3.0.0-M1]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1290) ~[spring-boot-3.0.0-M1.jar:3.0.0-M1]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1279) ~[spring-boot-3.0.0-M1.jar:3.0.0-M1]
	at com.allinprogram.***.Application.main(Application.java:12) ~[classes/:na]
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.dtflys.forest.springboot.ForestBeanRegister]: Factory method 'getForestBeanRegister' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'forestConfiguration': Bean instantiation via factory method failed; nested exception is java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:161) ~[spring-beans-6.0.0-M2.jar:6.0.0-M2]
	at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:630) ~[spring-beans-6.0.0-M2.jar:6.0.0-M2]
	... 19 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'forestConfiguration': Bean instantiation via factory method failed; nested exception is java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException
	at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:634) ~[spring-beans-6.0.0-M2.jar:6.0.0-M2]
	at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:622) ~[spring-beans-6.0.0-M2.jar:6.0.0-M2]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1310) ~[spring-beans-6.0.0-M2.jar:6.0.0-M2]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1161) ~[spring-beans-6.0.0-M2.jar:6.0.0-M2]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:566) ~[spring-beans-6.0.0-M2.jar:6.0.0-M2]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:526) ~[spring-beans-6.0.0-M2.jar:6.0.0-M2]
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[spring-beans-6.0.0-M2.jar:6.0.0-M2]
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.0.0-M2.jar:6.0.0-M2]
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[spring-beans-6.0.0-M2.jar:6.0.0-M2]
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) ~[spring-beans-6.0.0-M2.jar:6.0.0-M2]
	at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1138) ~[spring-context-6.0.0-M2.jar:6.0.0-M2]
	at com.dtflys.forest.springboot.ForestBeanRegister.registerForestConfiguration(ForestBeanRegister.java:134) ~[forest-spring-boot-starter-1.5.19.jar:na]
	at com.dtflys.forest.springboot.ForestAutoConfiguration.getForestBeanRegister(ForestAutoConfiguration.java:42) ~[forest-spring-boot-starter-1.5.19.jar:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:130) ~[spring-beans-6.0.0-M2.jar:6.0.0-M2]
	... 20 common frames omitted
Caused by: java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException
	at com.dtflys.forest.config.ForestConfiguration.createConfiguration(ForestConfiguration.java:336) ~[forest-core-1.5.19.jar:na]
	at com.dtflys.forest.config.ForestConfiguration.configuration(ForestConfiguration.java:320) ~[forest-core-1.5.19.jar:na]
	at com.dtflys.forest.config.ForestConfiguration.configuration(ForestConfiguration.java:306) ~[forest-core-1.5.19.jar:na]
	at com.dtflys.forest.config.ForestConfiguration.<clinit>(ForestConfiguration.java:99) ~[forest-core-1.5.19.jar:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:130) ~[spring-beans-6.0.0-M2.jar:6.0.0-M2]
	at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:630) ~[spring-beans-6.0.0-M2.jar:6.0.0-M2]
	... 37 common frames omitted
Caused by: java.lang.ClassNotFoundException: javax.xml.bind.JAXBException
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641) ~[na:na]
	at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188) ~[na:na]
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520) ~[na:na]
	... 47 common frames omitted

Disconnected from the target VM, address: '127.0.0.1:50713', transport: 'socket'

Process finished with exit code 1

I may have found some helpful information: https://stackoverflow.com/questions/43574426/how-to-resolve-java-lang-noclassdeffounderror-javax-xml-bind-jaxbexception

Please contact me if you need more information about the exception.

The singleton of httpclient

I think the httpclient/okhttpclient should singleton in connectionManager. Now the per request has a client. It’s so heavy and the most import is that the connection pool of client doesn‘t work.

模板表达式--变量引用名不支持特殊符号

有一个这样的配置,读取就会报错

forest:
  variables:
    xxx-search: http://baidu.com

版本:

<dependency>
    <groupId>com.dtflys.forest</groupId>
    <artifactId>forest-spring-boot-starter</artifactId>
    <version>1.5.2-BETA</version>
</dependency>

错别字

基础->请求对象->构建请求
image

不支持Kotlin?

forst 1.5.21,java 17,kotlin 1.6.10,springboot 2.7.0 启动报错

2022-05-29 16:33:02.677 [main] WARN o.s.b.w.s.c.AnnotationConfigServletWebServerApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'Test': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'client': FactoryBean threw exception on object creation; nested exception is java.lang.StackOverflowError 2022-05-29 16:33:02.679 [main] INFO o.a.catalina.core.StandardService - Stopping service [Tomcat] 2022-05-29 16:33:02.714 [main] ERROR o.s.boot.SpringApplication - Application run failed org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'Test': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'client': FactoryBean threw exception on object creation; nested exception is java.lang.StackOverflowError at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessProperties(CommonAnnotationBeanPostProcessor.java:332) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1431) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:619) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:953) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:734) at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408) at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) at com.liusibo.blog.BlogApplicationKt.main(BlogApplication.kt:15) Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'client': FactoryBean threw exception on object creation; nested exception is java.lang.StackOverflowError at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:176) at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:101) at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1884) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getObjectForBeanInstance(AbstractAutowireCapableBeanFactory.java:1284) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:267) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:213) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.resolveBeanByName(AbstractAutowireCapableBeanFactory.java:479) at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:550) at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:520) at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:673) at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:228) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119) at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessProperties(CommonAnnotationBeanPostProcessor.java:329) ... 17 common frames omitted Caused by: java.lang.StackOverflowError: null at java.base/java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:936) at java.base/java.lang.ClassLoader.definePackage(ClassLoader.java:2096) at java.base/java.lang.ClassLoader.definePackage(ClassLoader.java:2079) at java.base/java.lang.Class.getPackage(Class.java:1045) at com.dtflys.forest.reflection.ForestMethod.getAnnotationLifeCycleClassMap(ForestMethod.java:302) at com.dtflys.forest.reflection.ForestMethod.getAnnotationLifeCycleClassMap(ForestMethod.java:308) at com.dtflys.forest.reflection.ForestMethod.getAnnotationLifeCycleClassMap(ForestMethod.java:308) at com.dtflys.forest.reflection.ForestMethod.getAnnotationLifeCycleClassMap(ForestMethod.java:308) at com.dtflys.forest.reflection.ForestMethod.getAnnotationLifeCycleClassMap(ForestMethod.java:308) at com.dtflys.forest.reflection.ForestMethod.getAnnotationLifeCycleClassMap(ForestMethod.java:308)

ForestHandlerException 异常不支持捕获问题

官方提供的例子:
public class ErrorInterceptor implements Interceptor {
@OverRide
public void onError(ForestRuntimeException ex, ForestRequest request, ForestResponse response) {
int status = response.getStatusCode(); // 获取请求响应状态码
String content = response.getContent(); // 获取请求的响应内容
Object result = response.getResult(); // 获取方法返回类型对应的返回数据结果
}
}
onError无法捕获ForestHandlerException异常

拦截器修改body体内容导致@JSONField注解失效

forest version:v1.5.16

使用拦截器添加body体参数,如下:

public class UnitySignInterceptor implements Interceptor {

    @Override
    public boolean beforeExecute(ForestRequest request) {

        Map<String, Object> addMap = new HashMap<>();
        addMap.put("version", "text");
        request.addBody(JSON.toJSONString(addMap));

        return Interceptor.super.beforeExecute(request);
    }
    
}

实体字段如下:

@JSONField(format = "yyyy-MM-dd'T'HH:mm:ss")
private LocalDateTime createDateTime;

补救方案,配置全局时间格式化配置对 LocalDateTime 类型无效:

forest:
  converters:
    json:
      type: com.dtflys.forest.converter.json.ForestFastjsonConverter
      # 转换器的参数设置
      parameters:
        # JSON数据转换器的全局日期格式化配置
        dateFormat: "yyyy-MM-dd'T'HH:mm:ss"

请问还有其他解决方案吗?

请求发出后接收不到响应

版本:

com.dtflys.forest
forest-spring-boot-starter
1.5.0

描述:
在对接信用卡支付的过程中,同步的向银行发送一个http请求,发现偶尔有拿到的响应为null的情况(银行那边确定有响应body)。
请求API:
image

看到issue里有onSuccess监听失败的情况,但是打印的content的内容也是null:
image

请问这个是什么问题,该如何解决(是否升级到1.5.2-BETA即可)?

ForestAutoConfiguration will cause ForestScannerRegister basePackages add extra path

version: 1.5.2.BETA springboot
ForestAutoConfiguration 会额外导致ForestScannerRegister 这个类加入额外的路径,不符合预期。
image
影响是,加入了额外的basePackages,那么接下来就会loadClass,也就是类会提前加载,但是项目里面,如果使用static静态变量去获取bean,就会有问题。也就是在先于springboot完全启动前,static被执行了,这样就会造成在初始化的时候,无法拿到对应的bean。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.