【问题标题】:Lucene 4 on Android errorLucene 4 上的 Android 错误
【发布时间】:2014-02-22 07:05:00
【问题描述】:

在将 Lucene 4 与 Android API 19 (4.4.2) 一起使用时,我遇到了这个错误。

Caused by: java.lang.IllegalArgumentException: A SPI class of type org.apache.lucene.codecs.Codec with name 'Lucene46' does not exist. You need to add the corresponding JAR file supporting this SPI to your classpath.The current classpath supports the following names: []
        at org.apache.lucene.util.NamedSPILoader.lookup(NamedSPILoader.java:109)
        at org.apache.lucene.codecs.Codec.forName(Codec.java:95)
        at org.apache.lucene.codecs.Codec.<clinit>(Codec.java:122) at org.apache.lucene.index.LiveIndexWriterConfig.<init>(LiveIndexWriterConfig.java:122) at org.apache.lucene.index.IndexWriterConfig.<init>(IndexWriterConfig.java:165)

这是https://stackoverflow.com/questions/18944634/running-lucene-4-4-on-android报告的类似错误

我迁移到 IntelliJ 上的 android-maven-plugin 是因为它是针对我的问题的建议解决方案,但我仍然遇到问题。这是我的 Maven pom.xml

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.johnbohne.chishiki</groupId>
<artifactId>Chishiki</artifactId>
<version>1.0-SNAPSHOT</version>

<packaging>jar</packaging>

<name>Chishiki</name>
<build>
    <sourceDirectory>src</sourceDirectory>
    <finalName>${project.artifactId}</finalName>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>com.jayway.maven.plugins.android.generation2</groupId>
                <artifactId>android-maven-plugin</artifactId>
                <version>3.8.2</version>
                <extensions>true</extensions>
            </plugin>
        </plugins>
    </pluginManagement>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>2.3.2</version>
            <configuration>
                <source>1.5</source><target>1.5</target>
            </configuration>
        </plugin>
    </plugins>
</build>

我知道 Lucene 3.0 可以与 Android 一起使用,但我不太确定 Lucene 4.0。有人知道如何让 Lucene 4.0 在 Android 中运行吗?

【问题讨论】:

  • 仍然没有发现错误,但最终使用了似乎可以编译的 Lucene 3.6

标签: java android maven intellij-idea lucene


【解决方案1】:

这是一种运行它的方法(它肯定不是最好的解决方案,但它确实有效):

  1. 从 lucene-core 中移除 org/apache/lucene/util/SPIClassIterator
  2. 将修补版本拖放到源代码树中
  3. 将 META-INF/services 文件添加到您的资产文件夹
  4. 手动合并重复的服务文件

我正在使用以下(已修补)版本

package org.apache.lucene.util;

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Locale;
import java.util.NoSuchElementException;
import java.util.ServiceConfigurationError;

/**
 * Helper class for loading SPI classes from classpath (META-INF files).
 * This is a light impl of {@link java.util.ServiceLoader} but is guaranteed to
 * be bug-free regarding classpath order and does not instantiate or initialize
 * the classes found.
 *
 * @lucene.internal
 */
public final class SPIClassIterator<S> implements Iterator<Class<? extends S>> {
  private static final String META_INF_SERVICES = "/assets/META-INF/services/";

  private final Class<S> clazz;
  private final ClassLoader loader;
  private final Enumeration<URL> profilesEnum;
  private Iterator<String> linesIterator;

  public static <S> SPIClassIterator<S> get(Class<S> clazz) {
    return new SPIClassIterator<S>(clazz, Thread.currentThread().getContextClassLoader());
  }

  public static <S> SPIClassIterator<S> get(Class<S> clazz, ClassLoader loader) {
    return new SPIClassIterator<S>(clazz, loader);
  }

  /** Utility method to check if some class loader is a (grand-)parent of or the same as another one.
   * This means the child will be able to load all classes from the parent, too. */
  public static boolean isParentClassLoader(final ClassLoader parent, ClassLoader child) {
    while (child != null) {
      if (child == parent) {
        return true;
      }
      child = child.getParent();
    }
    return false;
  }

  private SPIClassIterator(Class<S> clazz, ClassLoader loader) {
    this.clazz = clazz;
    final String fullName = META_INF_SERVICES + clazz.getName();
    this.profilesEnum = 
      Collections.enumeration(
        Arrays.asList(new URL[]{getClass().getResource(fullName)}));
    this.loader = (loader == null) ? ClassLoader.getSystemClassLoader() : loader;
    this.linesIterator = Collections.<String>emptySet().iterator();
  }

  private boolean loadNextProfile() {
    ArrayList<String> lines = null;
    while (profilesEnum.hasMoreElements()) {
      if (lines != null) {
        lines.clear();
      } else {
        lines = new ArrayList<String>();
      }
      final URL url = profilesEnum.nextElement();
      try {
        final InputStream in = url.openStream();
        IOException priorE = null;
        try {
          final BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
          String line;
          while ((line = reader.readLine()) != null) {
            final int pos = line.indexOf('#');
            if (pos >= 0) {
              line = line.substring(0, pos);
            }
            line = line.trim();
            if (line.length() > 0) {
              lines.add(line);
            }
          }
        } catch (IOException ioe) {
          priorE = ioe;
        } finally {
          IOUtils.closeWhileHandlingException(priorE, in);
        }
      } catch (IOException ioe) {
        throw new ServiceConfigurationError("Error loading SPI class list from URL: " + url, ioe);
      }
      if (!lines.isEmpty()) {
        this.linesIterator = lines.iterator();
        return true;
      }
    }
    return false;
  }

  @Override
  public boolean hasNext() {
    return linesIterator.hasNext() || loadNextProfile();
  }

  @Override
  public Class<? extends S> next() {
    // hasNext() implicitely loads the next profile, so it is essential to call this here!
    if (!hasNext()) {
      throw new NoSuchElementException();
    }
    assert linesIterator.hasNext();
    final String c = linesIterator.next();
    try {
      // don't initialize the class (pass false as 2nd parameter):
      return Class.forName(c, false, loader).asSubclass(clazz);
    } catch (ClassNotFoundException cnfe) {
      throw new ServiceConfigurationError(String.format(Locale.ROOT, "A SPI class of type %s with classname %s does not exist, "+
        "please fix the file '%s%1$s' in your classpath.", clazz.getName(), c, META_INF_SERVICES));
    }
  }

  @Override
  public void remove() {
    throw new UnsupportedOperationException();
  }

}

所需的更改?

  1. META_INF_SERVICES 指向 /assets/META-INF/services/ 而不是 META-INF/services/
  2. 构造函数不同

编辑:这适用于 lucene 4.7.1。我现在只是确定它可以创建一个空目录,我不确定索引是否完全有效。

编辑 2:我现在可以确认它确实有效。至少手动查询创建和索引创建按预期工作。

编辑 3:基于此,我刚刚完成了自己的联系人合并。如果您有兴趣,可以在github/rtreffer/ContactMerger 获得源代码。

编辑 4:我现在可以在没有修补 jar 的情况下进行构建。我只是将 SPI 加载器放在 src 文件夹中,禁用库预索引并让 dx 完成它的工作。它速度较慢,但​​ src / classes 实现获胜,我可以从 maven Central 中提取所有依赖项。详情请见build.gradle

【讨论】:

  • 我尝试使用你正在做的事情,但它在 gradle build 上显示“已经添加:Lorg/apache/lucene/util/SPIClassIterator”
  • @John61590 查看 gradle 文件,我使用的是 pickFirst 'org/apache/lucene/util/SPIClassIterator.class'
  • @traffer 是的,我知道,但它仍然说同样的话。我复制了您在应用程序中的架构,但它不适用于更高的 gradle 构建。我使用的是 Lucene 4.7.1
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-06
  • 2016-06-08
  • 1970-01-01
  • 2013-03-13
相关资源
最近更新 更多