0

I have this OpenSearch code:

import org.opensearch.client.opensearch.OpenSearchClient;
import org.opensearch.client.opensearch.core.GetResponse;


private OpenSearchClient client;

private Optional<GetResponse> getDocumentResponse(BaseIndexDto request, String... indices) {
    try {
      final String indexName = this.getIndexName(indices);
      GetRequest getRequest = new GetRequest.Builder()
                .index(indexName)
                .id(request.getId())
                .build();
      GetResponse<GetResponse> response = client.get(getRequest, GetResponse.class);
      if (response.found()) {
        return Optional.of(response);
      } else {
        return Optional.empty();
      }
    } catch (Exception e) {
      throw Exception("Error");
    }
  }

I want to edit it this way:

private Optional<GetResponse<Map<String, Object>>> getDocumentResponse(BaseIndexDto request, String... indices) {
    try {
      final String indexName = this.getIndexName(indices);
      GetRequest getRequest = new GetRequest.Builder()
                .index(indexName)
                .id(request.getId())
                .build();
      GetResponse<Map<String, Object>> response = client.get(getRequest, GetResponse.class);
      if (response.found()) {
        return Optional.of(response);
      } else {
        return Optional.empty();
      }
    } catch (Exception e) {
     throw Exception("Error");
    }
  }

But I get error:

Required type: GetResponse<Map<String, Object>>
Provided: GetResponse <GetResponse>
Incompatible equality constraint: Map<String, Object> and GetResponse

I need something like this:

  GetResponse<Map<String, Object>> response = client.get(getRequest, GetResponse<Map<String, Object>>.class);

What is the correct way to implement this?

EDIT:

How I can implement a solution without this casting:

private Optional<GetResponse<Map<String, Object>>> getDocumentResponse(BaseIndexDto request, String... indices) {
    try {
      final String indexName = this.getIndexName(indices);
      GetRequest getRequest = new GetRequest.Builder()
                .index(indexName)
                .id(request.getId())
                .build();

      GetResponse<Object> response = client.get(getRequest, Object.class);

      if (response.found()) {
        GetResponse<Map<String, Object>> typedResponse = castGetResponse(response, Map.class);
        return Optional.of(typedResponse);
      } else {
        return Optional.empty();
      }
    } catch (Exception e) {
      throw Exception();
    }
  }

    private <T> GetResponse<T> castGetResponse(GetResponse<?> response, Class<Map> clazz) {
        return (GetResponse<T>) response;
    }
7
  • Did you try using just client.get(getRequest, GetResponse.class)? The same as before you changed to Map Commented Nov 24 at 21:23
  • Yes, I get Required type: GetResponse <Map<String, Object>> Provided: GetResponse <GetResponse> Incompatible equality constraint: Map<String, Object> and GetResponse Commented Nov 24 at 21:36
  • 1
    The API of opensearch is fundamentally incompatible with what you're trying to do. You can only request generics-less values. You have 2 options: [1] Do exactly that; make your own class that then contains that map, for example, or [2] add the ugly cast (save the response as a generics-less GetResponse then assign that variable to another variable of the right type, adding a cast. This will cause a warning. Suppress that. It's ugly and means the compiler will not verify types for this method. Commented Nov 25 at 0:03
  • I added edited solution. Is there some better way? Commented Nov 25 at 0:08
  • 1
    The correct way to do this, with no compiler warnings, is: GetResponse<?> response = (GetResponse<?>) client.get(getRequest, GetResponse.class); Map<?, ?> map = (Map<?, ?>) response.source(); Map<String, Object> typedMap = map.entrySet().stream().collect(Collectors.toMap(e -> (String) e.getKey(), e -> e.getValue())); If this seems unwieldy, it’s because programs are not supposed to use raw types in the first place. Commented Nov 25 at 18:43

1 Answer 1

0

The correct way to do this, with no compiler warnings, is:

GetResponse<?> response =
    (GetResponse<?>) client.get(getRequest, GetResponse.class);
Map<?, ?> map = (Map<?, ?>) response.source();
Map<String, Object> typedMap = map.entrySet().stream().collect(
    Collectors.toMap(e -> (String) e.getKey(), e -> e.getValue()));

If this seems unwieldy, it’s because programs are not supposed to use raw types in the first place.

Generic types do not exist as actual classes at runtime, so any cast to a generic type is unsafe unless its type arguments are all ? (which tells the compiler “don’t assume anything about the generic part”).

On the other hand, an actual cast like (String) e.getKey() is safe, because it’s casting to a class and not to a generic type. This will correctly throw an exception if the key is not actually a String, which is what you want.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.