Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@SpringQueryMap doesn't work with String[] #318

Closed
rkovtiuk opened this issue Apr 9, 2020 · 9 comments
Closed

@SpringQueryMap doesn't work with String[] #318

rkovtiuk opened this issue Apr 9, 2020 · 9 comments
Assignees

Comments

@rkovtiuk
Copy link

rkovtiuk commented Apr 9, 2020

Describe the bug
@SpringQueryMap doesn't support String[], but as @RequestParam String[] is working.

Sample
Fiegn client interface with two different API methods

@FeignClient
public interface ApiClient {

    @GetMapping("/incorrect")
    ApiResponse<ResponseDto> findAll(@SpringQueryMap ApiParams params);

    @PostMapping("/correct")
    ApiResponse<ResponseDto> findMarkingCodes(@RequestParam String[] fields);

}

ApiParams class

@Data
@AllArgsConstructor
public class ApiParams {
    private String[] fields;
}

Expected Behaviour
Expected url for request with @SpringQueryMap:
https://url/incorrect?fields=name,surname
Generated url for request with @SpringQueryMap:
https://url/incorrect?fields=%5BLjava.lang.String%3B%405ed08faf&b=%5BLjava.lang.String%3B%4075386aa2

But when I'm trying to use String[], it works and generated url is as expected:
https://url/correct?fields=name,surname

@MissingNone
Copy link

You can implements the QueryMapEncoder interface.

public class FormQueryMapEncoder implements QueryMapEncoder {
    private MappingJackson2HttpMessageConverter converter;
    public FormQueryMapEncoder(MappingJackson2HttpMessageConverter converter) {
        this.converter = converter;
    }
    @Override
    public Map<String, Object> encode(Object object) {
        Map<String, Object> ret = converter.getObjectMapper().convertValue(object,HashMap.class);
        return ret;
    }
}

And then declare a QueryMapEncoder bean in JavaConfig.

@Bean
QueryMapEncoder queryMapEncoder() {
       return new FormQueryMapEncoder(mappingJackson2HttpMessageConverter);
 }

@OlgaMaciaszek
Copy link
Collaborator

@rkovtiuk Does the provided workaround solve your issue?

@rkovtiuk
Copy link
Author

Hi @MissingNone, @OlgaMaciaszek,
No, it doesn't.
I tried this example and see same:
fields=%5BLjava.lang.String%3B%40e35dc14

I also tried this variant:

@Bean
public QueryMapEncoder queryMapEncoder(ObjectMapper objectMapper) {
   return object -> objectMapper.convertValue(object, new TypeReference<Map<String, Object>>() {});
}

But this also doesn't help.

@MissingNone
Copy link

@rkovtiuk But I tried this is worked.
Maybe Encoder is different with me.

config file:

@Configuration
public class CoreFeignConfiguration {
    @Autowired
    private ObjectFactory<HttpMessageConverters> messageConverters;
    @Autowired
    private MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter;

    @Bean
    @Primary
    @Scope(SCOPE_PROTOTYPE)
    Encoder feignFormEncoder() {
        return new SpringFormEncoder(new SpringEncoder(messageConverters));
    }
    @Bean
    QueryMapEncoder queryMapEncoder() {
        return new FormQueryMapEncoder(mappingJackson2HttpMessageConverter);
    }

}

FormQueryMapEncoder.java

public class FormQueryMapEncoder implements QueryMapEncoder {
    private MappingJackson2HttpMessageConverter converter;
    public FormQueryMapEncoder(MappingJackson2HttpMessageConverter converter) {
        this.converter = converter;
    }
    @Override
    public Map<String, Object> encode(Object object) {
        Map<String, Object> ret = converter.getObjectMapper().convertValue(object,HashMap.class);
        return ret;
    }
}

version: spring-cloud-stater-openfeign:2.2.2.RELEASE

Can you provide a demo for your issue?

@rkovtiuk
Copy link
Author

My configuration

@Configuration
public class FeignConfiguration {

    @Autowired
    private ObjectFactory<HttpMessageConverters> messageConverters;

    @Bean
    public QueryMapEncoder queryMapEncoder(ObjectMapper objectMapper) {
        return object -> objectMapper.convertValue(object, new TypeReference<Map<String, Object>>() {});
    }

    @Bean
    @Primary
    @Scope(SCOPE_PROTOTYPE)
    public Encoder feignFormEncoder() {
        return new SpringFormEncoder(new SpringEncoder(messageConverters));
    }

    @Bean
    public Client feignClient() {
        return new Client.Default(getSSLSocketFactory(), new NoopHostnameVerifier());
    }

    private SSLSocketFactory getSSLSocketFactory() {
        try {
            var sslContext = SSLContexts.custom().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build();
            return sslContext.getSocketFactory();
        } catch (Exception exception) {
            throw new RuntimeException(exception);
        }
    }

}

version: 2.1.2.RELEASE

@MissingNone
Copy link

MissingNone commented Apr 20, 2020

@rkovtiuk I used your version for project And find out it.

Beacause Feign still used default QueryMapEncoder instead of Our QueryMapEncoder bean before spring-cloud-stater-openfeign:2.0.0.M3.

So adding the Feign.Builder bean based on the previous then it worked on your version.

new configuration:

@Configuration
public class CoreFeignConfiguration {
    @Autowired
    private ObjectFactory<HttpMessageConverters> messageConverters;

    @Bean
    @Primary
    @Scope(SCOPE_PROTOTYPE)
    Encoder feignFormEncoder() {
        return new SpringFormEncoder(new SpringEncoder(messageConverters));
    }
    @Bean
    QueryMapEncoder queryMapEncoder(ObjectMapper objectMapper) {
        return object-> objectMapper.convertValue(object, new TypeReference<Map<String, Object>>() {});
    }

    @Bean
    @Scope(SCOPE_PROTOTYPE)
    public Feign.Builder feignBuilder(QueryMapEncoder queryMapEncoder) {
        return Feign.builder().queryMapEncoder(queryMapEncoder);
    }

}

@rkovtiuk
Copy link
Author

@MissingNone, this configuration works for me
thanks 😃

@Configuration
public class FeignConfiguration {

    @Bean
    public QueryMapEncoder queryMapEncoder(ObjectMapper objectMapper) {
        return object -> objectMapper.convertValue(object, new TypeReference<Map<String, Object>>() {});
    }

    @Bean
    @Scope(SCOPE_PROTOTYPE)
    public Feign.Builder feignBuilder(QueryMapEncoder queryMapEncoder) {
        return Feign.builder().queryMapEncoder(queryMapEncoder);
    }
}

But as I understood, this must work without this additional configuration.

@MissingNone
Copy link

@rkovtiuk Yes,it's a bug. your issue is same as the issue #256.Issue OpenFeign/feign#1170 mentioned it.

@OlgaMaciaszek
Copy link
Collaborator

Closing in favour of OpenFeign/feign#1170.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants