1

I'm trying to create a custom elasticsearch plugin using scala by following the following tutorial (which is in Java).

public class PlusSignAnalyzerProvider extends
    AbstractIndexAnalyzerProvider {

        /* Constructor. Nothing special here. */
        @Inject
        public PlusSignAnalyzerProvider(Index index,
        @IndexSettings Settings indexSettings, Environment env,
        @Assisted String name, @Assisted Settings settings) throws IOException {
                super(index, indexSettings, name, settings);
        }

        /* This function needs to be overridden to return an instance of
         * PlusSignAnalyzer.
         */
        @Override
        public PlusSignAnalyzer get() {
            return this.analyzer;
        }

        /* Instance of PlusSignAnalyzer class that is returned by this class. */
        protected PlusSignAnalyzer analyzer = new PlusSignAnalyzer();

        /* Name to associate with this class. We will use this in
         * PlusSignBinderProcessor.
         */
        public static final String NAME = "plus_sign";
    }

Trying to achieve this in scala I did the following:

@Inject class PlusSignAnalyzerProvider(index: Index,
                                   @IndexSettings indexSettings: Settings,
                                   env: Environment,
                                   @AssistedInject @Assisted name: String,
                                   @AssistedInject @Assisted settings: Settings)
  extends AbstractIndexAnalyzerProvider[PlusSignAnalyzer](index, indexSettings, name, settings) {

  val analyzer: PlusSignAnalyzer = new PlusSignAnalyzer()

  def NAME = "plus_sign"

  override def get(): PlusSignAnalyzer = {
    this.analyzer
  }
}

which at runtime gives me an error:

Exception in thread "main" org.elasticsearch.common.inject.CreationException: Guice creation errors:

1) Could not find a suitable constructor in com.xxxxxx.yyyyyyy.es.plugins.PlusSignAnalyzerProvider. Classes must have either one (and only one) constructor annotated with @Inject or a zero-argument constructor that is not private.
at com.xxxxxx.yyyyyyy.es.plugins.PlusSignAnalyzerProvider.class(Unknown Source)
at _unknown_

1 error
    at org.elasticsearch.common.inject.internal.Errors.throwCreationExceptionIfErrorsExist(Errors.java:344)
    at org.elasticsearch.common.inject.InjectorBuilder.initializeStatically(InjectorBuilder.java:151)
    at org.elasticsearch.common.inject.InjectorBuilder.build(InjectorBuilder.java:102)
    at org.elasticsearch.common.inject.Guice.createInjector(Guice.java:93)
    at org.elasticsearch.common.inject.Guice.createInjector(Guice.java:70)
    at org.elasticsearch.common.inject.ModulesBuilder.createInjector(ModulesBuilder.java:59)
    at org.elasticsearch.node.internal.InternalNode.<init>(InternalNode.java:203)
    at org.elasticsearch.node.NodeBuilder.build(NodeBuilder.java:159)

[EDITED]: The following also doesn't work:

class PlusSignAnalyzerProvider @Inject() (index: Index,
                                   @IndexSettings indexSettings: Settings,
                                   env: Environment,
                                   @Assisted name: String,
                                   @Assisted settings: Settings)
extends AbstractIndexAnalyzerProvider[PlusSignAnalyzer](index, indexSettings,   name, settings) {

  val analyzer: PlusSignAnalyzer = new PlusSignAnalyzer()

  def NAME = "plus_sign"

  override def get(): PlusSignAnalyzer = {
    this.analyzer
  }
}

And the error thrown is:

  Exception in thread "main" org.elasticsearch.common.inject.CreationException: Guice creation errors:

1) No implementation for java.lang.String annotated with @org.elasticsearch.common.inject.assistedinject.Assisted(value=) was bound.
  while locating java.lang.String annotated with @org.elasticsearch.common.inject.assistedinject.Assisted(value=)
    for parameter 3 at com.xxxxxx.yyyyyyy.es.plugins.PlusSignAnalyzerProvider.<init>(Unknown Source)
  at _unknown_

2) No implementation for org.elasticsearch.common.settings.Settings annotated with @org.elasticsearch.common.inject.assistedinject.Assisted(value=) was bound.
  while locating org.elasticsearch.common.settings.Settings annotated with @org.elasticsearch.common.inject.assistedinject.Assisted(value=)
    for parameter 4 at com.xxxxxx.yyyyyyy.es.plugins.PlusSignAnalyzerProvider.<init>(Unknown Source)
  at _unknown_

3) No implementation for org.elasticsearch.common.settings.Settings annotated with @org.elasticsearch.index.settings.IndexSettings() was bound.
  while locating org.elasticsearch.common.settings.Settings annotated with @org.elasticsearch.index.settings.IndexSettings()
    for parameter 1 at com.xxxxxx.yyyyyyy.es.plugins.PlusSignAnalyzerProvider.<init>(Unknown Source)
  at _unknown_

4) Could not find a suitable constructor in org.elasticsearch.index.Index. Classes must have either one (and only one) constructor annotated with @Inject or a zero-argument constructor that is not private.
  at org.elasticsearch.index.Index.class(Unknown Source)
  while locating org.elasticsearch.index.Index
    for parameter 0 at com.xxxxxx.yyyyyyy.es.plugins.PlusSignAnalyzerProvider.<init>(Unknown Source)
  at _unknown_

4 errors
    at org.elasticsearch.common.inject.internal.Errors.throwCreationExceptionIfErrorsExist(Errors.java:344)
    at org.elasticsearch.common.inject.InjectorBuilder.initializeStatically(InjectorBuilder.java:151)
    at org.elasticsearch.common.inject.InjectorBuilder.build(InjectorBuilder.java:102)
    at org.elasticsearch.common.inject.Guice.createInjector(Guice.java:93)
    at org.elasticsearch.common.inject.Guice.createInjector(Guice.java:70)
    at org.elasticsearch.common.inject.ModulesBuilder.createInjector(ModulesBuilder.java:59)
    at org.elasticsearch.node.internal.InternalNode.<init>(InternalNode.java:203)
    at org.elasticsearch.node.NodeBuilder.build(NodeBuilder.java:159)

On googling I ended up in SO links 2, 3

But unfortunately, being a newbie I couldn't make out much out of it and rid my error. Can someone point me what needs to be rectified here.

[EDITED:] Including the code for Module Object as well.

import org.elasticsearch.common.inject.AbstractModule

class PlusSignBinderModule extends AbstractModule {
  override def configure(): Unit = {
    bind(classOf[PlusSignAnalyzerProvider]).asEagerSingleton()
  }
}

Code for Plugin:

class MyFirstAnalyzerPlugin extends AbstractPlugin {
  override def description(): String = {
    "Custom elasticsearch analyzer plugin"
  }

  override def name(): String = {
    "my-analyzer"
  }

  override def modules(): Collection[Class[_ <: Module]] = {
    val modules: Collection[Class[_ <: Module]] = Lists.newArrayList()
    modules.add(classOf[PlusSignBinderModule])
    modules
  }
}
Community
  • 1
  • 1
gashu
  • 484
  • 6
  • 17

1 Answers1

1

Try this instead:

class PlusSignAnalyzerProvider @AssistedInject() (index: Index,
                                   @IndexSettings indexSettings: Settings,
                                   env: Environment,
                                   @Assisted name: String,
                                   @Assisted settings: Settings)
  extends AbstractIndexAnalyzerProvider[PlusSignAnalyzer](index, indexSettings, name, settings) {

  val analyzer: PlusSignAnalyzer = new PlusSignAnalyzer()

  def NAME = "plus_sign"

  override def get(): PlusSignAnalyzer = {
    this.analyzer
  }
}

The annotation is on the constructor rather than the class object. You need the extra set of parens so that it doesn't try to use your various arguments as part of the construction of the Inject annotation.

You will also need to make sure the other elements in there are bound (Index, Settings, and Environment)—which since you haven't posted your Module object I can't tell whether they are bound correctly, as well as that you are using the correct semantics for doing assisted inject correctly.

David H. Clements
  • 3,590
  • 2
  • 24
  • 26
  • Edited the original post to include the Module as well (at the bottom of ques.) – gashu Apr 10 '15 at 07:20
  • Also, the output of the code you asked me to try is as: `Exception in thread "main" org.elasticsearch.common.inject.CreationException: Guice creation errors: 1) Could not find a suitable constructor in com.xxxxxx.yyyyyyy.es.plugins. PlusSignAnalyzerProvider. Classes must have either one (and only one) constructor annotated with @Inject or a zero-argument constructor that is not private. at com.xxxxxx.yyyyyyy.es.plugins. PlusSignAnalyzerProvider.class(Unknown Source) at _unknown_` – gashu Apr 10 '15 at 07:22
  • The stack is: `1 error at org.elasticsearch.common.inject.internal.Errors.throwCreationExceptionIfErrorsExist(Errors.java:344) at org.elasticsearch.common.inject.InjectorBuilder.initializeStatically(InjectorBuilder.java:151) at org.elasticsearch.common.inject.InjectorBuilder.build(InjectorBuilder.java:102) at org.elasticsearch.common.inject.Guice.createInjector(Guice.java:93) at org.elasticsearch.common.inject.Guice.createInjector(Guice.java:70) at org.elasticsearch.common.inject.ModulesBuilder.createInjector(ModulesBuilder.java:59) at org.elasticsearch.node.internal.InternalNode. – gashu Apr 10 '15 at 07:25