0

I am currently updating my ElasticSearch FieldMapper plugin for accepting a TokenStream in JSON format to ES version 7.17. I copied most of it from the TextFieldPlugin because the Preanalyzed format is meant to contain longer text, but completely preanalyzed as a TokenStream.

All tests work fine. However, when I deploy the plugin in an ElasticSearch server, I get an IllegalAccessException when trying to create an index that contains a preanalyzed field, thus, engages the PreanalyzedFieldMapper:

java.lang.IllegalAccessError: class org.elasticsearch.index.mapper.PreanalyzedFieldMapper tried to access protected method 'void org.elasticsearch.index.mapper.FieldMapper$Parameter.toXContent(org.elasticsearch.xcontent.XContentBuilder, boolean)' (org.elasticsearch.index.mapper.PreanalyzedFieldMapper is in unnamed module of loader java.net.FactoryURLClassLoader @652b3733; org.elasticsearch.index.mapper.FieldMapper$Parameter is in unnamed module of loader 'app')
    at org.elasticsearch.index.mapper.PreanalyzedFieldMapper.doXContentBody(PreanalyzedFieldMapper.java:1255)
    at org.elasticsearch.index.mapper.FieldMapper.toXContent(FieldMapper.java:434)
    at org.elasticsearch.index.mapper.ObjectMapper.serializeMappers(ObjectMapper.java:431)
    at org.elasticsearch.index.mapper.ObjectMapper.toXContent(ObjectMapper.java:416)
    at org.elasticsearch.index.mapper.ObjectMapper.toXContent(ObjectMapper.java:394)
    at org.elasticsearch.index.mapper.ObjectMapper.serializeMappers(ObjectMapper.java:431)
    at org.elasticsearch.index.mapper.ObjectMapper.toXContent(ObjectMapper.java:416)
    at org.elasticsearch.index.mapper.Mapping.toXContent(Mapping.java:176)
    at org.elasticsearch.common.compress.CompressedXContent.<init>(CompressedXContent.java:96)
    at org.elasticsearch.index.mapper.Mapping.toCompressedXContent(Mapping.java:77)
    at org.elasticsearch.index.mapper.DocumentMapper.<init>(DocumentMapper.java:35)
    at org.elasticsearch.index.mapper.MapperService.newDocumentMapper(MapperService.java:460)
    at org.elasticsearch.index.mapper.MapperService.applyMappings(MapperService.java:440)
    at org.elasticsearch.index.mapper.MapperService.mergeAndApplyMappings(MapperService.java:421)
    at org.elasticsearch.index.mapper.MapperService.merge(MapperService.java:402)
    at org.elasticsearch.cluster.metadata.MetadataCreateIndexService.updateIndexMappingsAndBuildSortOrder(MetadataCreateIndexService.java:1303)
    at org.elasticsearch.cluster.metadata.MetadataCreateIndexService.lambda$applyCreateIndexWithTemporaryService$3(MetadataCreateIndexService.java:453)
    at org.elasticsearch.indices.IndicesService.withTempIndexService(IndicesService.java:673)
    at org.elasticsearch.cluster.metadata.MetadataCreateIndexService.applyCreateIndexWithTemporaryService(MetadataCreateIndexService.java:451)
    at org.elasticsearch.cluster.metadata.MetadataCreateIndexService.applyCreateIndexRequestWithV1Templates(MetadataCreateIndexService.java:567)
    at org.elasticsearch.cluster.metadata.MetadataCreateIndexService.applyCreateIndexRequest(MetadataCreateIndexService.java:413)
    at org.elasticsearch.cluster.metadata.MetadataCreateIndexService.applyCreateIndexRequest(MetadataCreateIndexService.java:420)
    at org.elasticsearch.cluster.metadata.MetadataCreateIndexService$1.execute(MetadataCreateIndexService.java:319)
    at org.elasticsearch.cluster.ClusterStateUpdateTask.execute(ClusterStateUpdateTask.java:51)
    at org.elasticsearch.cluster.service.MasterService.executeTasks(MasterService.java:840)
    at org.elasticsearch.cluster.service.MasterService.calculateTaskOutputs(MasterService.java:407)
    at org.elasticsearch.cluster.service.MasterService.runTasks(MasterService.java:243)
    at org.elasticsearch.cluster.service.MasterService.access$100(MasterService.java:63)
    at org.elasticsearch.cluster.service.MasterService$Batcher.run(MasterService.java:170)
    at org.elasticsearch.cluster.service.TaskBatcher.runIfNotProcessed(TaskBatcher.java:146)
    at org.elasticsearch.cluster.service.TaskBatcher$BatchedTask.run(TaskBatcher.java:202)
    at org.elasticsearch.common.util.concurrent.ThreadContext$ContextPreservingRunnable.run(ThreadContext.java:718)
    at org.elasticsearch.common.util.concurrent.PrioritizedEsThreadPoolExecutor$TieBreakingPrioritizedRunnable.runAndClean(PrioritizedEsThreadPoolExecutor.java:262)
    at org.elasticsearch.common.util.concurrent.PrioritizedEsThreadPoolExecutor$TieBreakingPrioritizedRunnable.run(PrioritizedEsThreadPoolExecutor.java:225)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
    at java.base/java.lang.Thread.run(Thread.java:1589)
    Suppressed: java.lang.IllegalStateException: Failed to close the XContentBuilder
        at org.elasticsearch.xcontent.XContentBuilder.close(XContentBuilder.java:1131)
        at org.elasticsearch.common.compress.CompressedXContent.<init>(CompressedXContent.java:92)
        ... 28 more
    Caused by: java.io.IOException: Unclosed object or array found
        at org.elasticsearch.xcontent.json.JsonXContentGenerator.close(JsonXContentGenerator.java:456)
        at org.elasticsearch.xcontent.XContentBuilder.close(XContentBuilder.java:1129)
        ... 29 more

The issue seems to be that my method doXContentBody() - which is really copied from the TextFieldMapper - tries to serialize its Parameter objects that are instances of an inner class in the mapper super class FieldMapper and have the protected method toXContent that is called in "my" method to serialize the whole mapper with its parameters.

Now I know why this doesn't work: My plugin lies in its own JAR file apart from the ElasticSearch core JARs and is loaded with another class loader. Thus, it does not have access to the protected fields and methods of the inner classes of its super class (Parameter is an inner class of FieldMapper).

My basic question here is: How is this meant to work? I tried to check out other ES Mapping Plugins but they just don't implement the doXContentBody() method. I am unclear about the consequences about implementing or not implementing it and so I am at a loss here. Must I implement it? How could I do it without access to the toXContent() method of the FieldMapper.Parameter class? What happens if I don't implement it?

My plugin code and the specific method can be found here: https://github.com/JULIELab/elasticsearch-mapper-preanalyzed/blob/86bd2b5cf9f3020231603ed5cc7bfcdb3feb6669/src/main/java/org/elasticsearch/index/mapper/PreanalyzedFieldMapper.java#L1241

As I said, it's in large parts a copy of ElasticSearch's TextFieldMapper class since it should behave like it. Perhaps that is an error to begin with. But in previous ES versions that worked fine. This issue with the protected parameter method is new to me.

khituras
  • 1,081
  • 10
  • 25

0 Answers0