当前位置: 首页 > 知识库问答 >
问题:

org.springframework.data.util.TypeInformation.isSubTypeOf(Ljava/lang/Class;)Z

司寇灵均
2023-03-14

我在Elasticsearch 7.4版中使用Spring数据Elasticsearch。马文:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        <version>2.1.7.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-elasticsearch</artifactId>
        <version>4.0.0.BUILD-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-commons</artifactId>
        <version>2.1.10.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.html" target="_blank">elasticsearch</groupId>
        <artifactId>elasticsearch</artifactId>
        <version>7.4.0</version>
    </dependency>
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-high-level-client</artifactId>
        <version>7.4.0</version>
    </dependency>
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-client</artifactId>
        <version>7.4.0</version>
    </dependency>

模型

@AllArgsConstructor
@NoArgsConstructor
@Data
@Document(indexName = "address", createIndex = true)
public class Address {
    @Id
    private String id;
    private String fullAddress;

    @Field(type = FieldType.Nested, store = true)
    private List<Entry> parts;

    public Address(String fullAddress) {
        this.fullAddress = fullAddress;
    }

    public Address(String fullAddress, List<Entry> entryList) {
        this.fullAddress = fullAddress;
        this.parts = entryList;
    }
}

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Entry {
    private String aoid;
    private String aoGuid;
    private String code;
    private String offName;
    private String parentGuid;
    private String shortName;
    @Field(type = FieldType.Integer)
    private Integer aoLevel;
    private String postalCode;
}

存储库:

@Repository
public interface AddressElasticRepository extends ElasticsearchRepository<Address, String> {
    List<Address> findByFullAddressContains(String fullAddress);
}

服务

@Service
public class SearchServiceImpl implements SearchService {
    private final AddressElasticRepository addressElasticRepository;

    public SearchServiceImpl(AddressElasticRepository addressElasticRepository) {
        this.addressElasticRepository = addressElasticRepository;
    }

    @Override
    public List<Document> search(String query) {
        List<Address> all = addressElasticRepository.findByFullAddressContains(query);
        all.forEach(it -> log.info("-- " + it.getFullAddress()));

        return null;
    }

    @Override
    public void save(Address address) {
        addressElasticRepository.save(address);
    }
}

控制器:

@Controller
public class SearchController {
    private final SearchService searchService;

    public SearchController(SearchService searchService) {
        this.searchService = searchService;
    }

    @RequestMapping(value = "/api/v1/fias/search", method = GET)
    public List<Document> search(@RequestParam String query) {
        return searchService.search(query);
    }
}

当我进行搜索时:localhost:8189/api/v1/fias/search?query=我收到一个错误:

JAVAlang.NoSuchMethodError:org。springframework。数据util。类型信息。isSubTypeOf(Ljava/lang/Class;)Z

错误发生在以下行(searchserviceinpl.java:23):List all=addressElasticRepository。findByFullAddressContains(查询);

如何修复它?

UPD:完整堆栈跟踪

UPD 2:在sping-data-Commons版本中出错。isSubTypeOf方法出现在版本2.2之后。如果我升级,应用程序不启动,这里是堆栈跟踪:

JAVAlang.NoSuchFieldError:在组织中导入\u BEAN\u名称\u生成器。springframework。数据存储库。配置。RepositoryBeanDefinitionRegisterSupport。registerBeanDefinitions(repositoryBeanDefinitionRegisterSupport.java:78)~[spring-data-commons-2.2.1.RELEASE.jar:2.2.1.RELEASE]位于org。springframework。上下文注释。ConfigurationClassBeanDefinitionReader。lambda$LoadBeanDefinitionsFromRegisters$0(ConfigurationClassBeanDefinitionReader.java:360)~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]在java上。util。LinkedHashMap。forEach(LinkedHashMap.java:684)~[na:1.8.0_201]位于org。springframework。上下文注释。ConfigurationClassBeanDefinitionReader。从注册器(ConfigurationClassBeanDefinitionReader.java:359)~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]在org上加载BeanDefinitions。springframework。上下文注释。ConfigurationClassBeanDefinitionReader。在org上加载BeanDefinitionsforConfiguration类(ConfigurationClassBeanDefinitionReader.java:144)~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]。springframework。上下文注释。ConfigurationClassBeanDefinitionReader。在org上加载BeanDefinitions(ConfigurationClassBeanDefinitionReader.java:117)~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]。springframework。上下文注释。配置类后处理器。processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:328)~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]位于org。springframework。上下文注释。配置类后处理器。postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:233)~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]位于org。springframework。上下文支持后处理器注册Legate。invokeBeanDefinitionRegistryPostProcessors(postProcessorRegistrationLegate.java:273)~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]位于org。springframework。上下文支持后处理器注册Legate。在org上调用ebeanfactorypostprocessors(postprocessorregistrationelegate.java:93)~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]。springframework。上下文支持AbstractApplicationContext。org上的invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:693)~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]。springframework。上下文支持AbstractApplicationContext。在org上刷新(AbstractApplicationContext.java:531)~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]。springframework。靴子网状物servlet。上下文ServletWebServerApplicationContext。在org上刷新(ServletWebServerApplicationContext.java:140)~[spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]。springframework。靴子SpringApplication。在org上刷新(SpringApplication.java:752)[spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]。springframework。靴子SpringApplication。refreshContext(SpringApplication.java:388)[spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]位于org。springframework。靴子SpringApplication。在org上运行(SpringApplication.java:327)[spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]。springframework。靴子SpringApplication。在org上运行(SpringApplication.java:1246)[spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]。springframework。靴子SpringApplication。在ru上运行(SpringApplication.java:1234)[spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]。伊沃伦塔。服务器共沉积应用。main(CoreFiasApplication.java:21)[classes/:na]

共有3个答案

夏高朗
2023-03-14

@你的建议帮助我做出了正确的决定。我仔细阅读了堆栈跟踪,并研究了我的Spring Boot版本的依赖关系。在Spring-boot-dependencies-2.0中。0.0发布。pom列出了5.6版。8用于ElasticSearch(我的7.4版)。我根据这个答案重写了我的代码-https://stackoverflow.com/a/58371997/9312228.一切都对我有用!我需要一个CustomElasticSearchConverter和一个配置了它的ElasticsearchRestTemplate。

    <dependency>
        <groupId>org.elasticsearch</groupId>
        <artifactId>elasticsearch</artifactId>
        <version>7.4.0</version>
    </dependency>
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-high-level-client</artifactId>
        <version>7.4.0</version>
    </dependency>
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-client</artifactId>
        <version>7.4.0</version>
    </dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
    <version>2.0.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-elasticsearch</artifactId>
    <version>4.0.0.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-commons</artifactId>
    <version>2.1.10.RELEASE</version>
</dependency>

class CustomElasticSearchConverter extends MappingElasticsearchConverter {

    private CustomConversions conversions = new ElasticsearchCustomConversions(Collections.emptyList());

    CustomElasticSearchConverter(MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext) {
        super(mappingContext);
        setConversions(conversions);
    }

    CustomElasticSearchConverter(MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext, GenericConversionService conversionService) {
        super(mappingContext, conversionService);
        setConversions(conversions);
    }

    @Override
    protected <R> R readValue(@Nullable Object source, ElasticsearchPersistentProperty property,
                              TypeInformation<R> targetType) {

        if (source == null) {
            return null;
        }

        if (source instanceof List) {
            return readCollectionValue((List) source, property, targetType);
        }

        return super.readValue(source, property, targetType);
    }

    private Object readSimpleValue(@Nullable Object value, TypeInformation<?> targetType) {

        Class<?> target = targetType.getType();

        if (value == null || target == null || ClassUtils.isAssignableValue(target, value)) {
            return value;
        }

        if (conversions.hasCustomReadTarget(value.getClass(), target)) {
            return getConversionService().convert(value, target);
        }

        if (Enum.class.isAssignableFrom(target)) {
            return Enum.valueOf((Class<Enum>) target, value.toString());
        }

        return getConversionService().convert(value, target);
    }


    private <R> R readCollectionValue(@Nullable List<?> source, ElasticsearchPersistentProperty property,
                                      TypeInformation<R> targetType) {

        if (source == null) {
            return null;
        }

        Collection<Object> target = createCollectionForValue(targetType, source.size());

        for (Object value : source) {

            if (isSimpleType(value)) {
                target.add(
                        readSimpleValue(value, targetType.getComponentType() != null ? targetType.getComponentType() : targetType));
            } else {

                if (value instanceof List) {
                    target.add(readValue(value, property, property.getTypeInformation().getActualType()));
                } else {
                    target.add(readEntity(computeGenericValueTypeForRead(property, value), (Map) value));
                }
            }
        }

        return (R) target;
    }

    private Collection<Object> createCollectionForValue(TypeInformation<?> collectionTypeInformation, int size) {

        Class<?> collectionType = collectionTypeInformation.isCollectionLike()//
                ? collectionTypeInformation.getType() //
                : List.class;

        TypeInformation<?> componentType = collectionTypeInformation.getComponentType() != null //
                ? collectionTypeInformation.getComponentType() //
                : ClassTypeInformation.OBJECT;

        return collectionTypeInformation.getType().isArray() //
                ? new ArrayList<>(size) //
                : CollectionFactory.createCollection(collectionType, componentType.getType(), size);
    }

    private ElasticsearchPersistentEntity<?> computeGenericValueTypeForRead(ElasticsearchPersistentProperty property,
                                                                            Object value) {

        return ClassTypeInformation.OBJECT.equals(property.getTypeInformation().getActualType())
                ? getMappingContext().getRequiredPersistentEntity(value.getClass())
                : getMappingContext().getRequiredPersistentEntity(property.getTypeInformation().getActualType());
    }

    private boolean isSimpleType(Object value) {
        return isSimpleType(value.getClass());
    }

    private boolean isSimpleType(Class<?> type) {
        return conversions.isSimpleType(type);
    }
}

我的配置:

@Bean
RestHighLevelClient elasticsearchClient() {
    return new RestHighLevelClient(RestClient.builder(
            new HttpHost(host, port)
    ));
}

@Primary
@Bean
public ElasticsearchRestTemplate elasticsearchTemplate() {
    CustomElasticSearchConverter converter = new CustomElasticSearchConverter(new SimpleElasticsearchMappingContext(), createConversionService());
    return new ElasticsearchRestTemplate(elasticsearchClient(), converter);
}

private DefaultConversionService createConversionService() {
    return new DefaultConversionService();
}

和发射器:

@SpringBootApplication(exclude = {ElasticsearchAutoConfiguration.class})
魏康安
2023-03-14

我认为你代码中的问题是:

@Repository
public interface AddressElasticRepository extends ElasticsearchRepository<Address, String> {
    List<Address> findByFullAddressContains(String fullAddress);
}

不使用包含,然后使用包含(而不是包含)。

请参阅Spring Data Elasticsearch查询创建和Spring Data JPA查询创建文档。

淳于慎之
2023-03-14

Spring数据Elasticsearch 4.0。0.BUILD-SNAPSHOT是根据SpringDataCommons 2.3构建的。0.0版本快照。您不应该使用旧的commons 2.1。10.在这里释放。

出于好奇:为什么要使用CustomElasticSearchConverter

至于配置,查看https://docs.spring.io/spring-data/elasticsearch/docs/4.0.0.M3/reference/html/#elasticsearch.clients.rest.

在进行自定义配置时,

@SpringBootApplication(exclude = {ElasticsearchAutoConfiguration.class})

是正确的道路。

编辑:

Spring数据elasticsearch 4.0。0.BUILD_快照不能与spring data commons 2.0一起使用。5.repositorybean定义注册支持。导入BEAN\u名称\u生成器是在Spring5.2中引入的。

因此,SpringDataElasticSearch4.0需要SpringDataCommons 2.3和Spring5.2。3.没有这些版本将导致您看到的错误。

 类似资料: