0

在我的 play framework v2.3.8 应用程序中进行 spring-data-solr 查询时,我一直遇到问题。查询似乎成功但随后使用的类加载器 spring 找不到我的数据模型类的类文件并抛出NoClassDefFoundError. 这是一些相关的代码。

首先是包'model'中的数据模型:

package model;

import org.apache.solr.client.solrj.beans.Field;
import org.springframework.data.annotation.Id;

public class Theatre
{
    @Id
    String id;

    @Field
    String docType;

    // other fields, getters, and setters omitted for brevity
}

这是存储库:

package model;

import java.util.List;

import org.springframework.data.solr.repository.SolrCrudRepository;

public interface TheatreRepository extends SolrCrudRepository<Theatre, String>
{
    List<Theatre> findByDocType(String doc__type);

    void delete(Theatre deleted);

    List<Theatre> findAll();

    Theatre findOne(String id);

    @SuppressWarnings("unchecked")
    Theatre save(Theatre persisted);
}

游戏框架中的应用程序类:

package controllers;

import java.util.ArrayList;
import java.util.List;

import model.Theatre;
import model.TheatreRepository;

import play.*;

import plugins.solr.SolrPlugin;
import views.html.*;

public class Application extends Controller {



    public static Result index() {

        TheatreRepository repository = Play.application().plugin( SolrPlugin.class ).getTheatreRepository();
        if( repository != null )
        {            
            List<Theatre> allTheatres = null;
            try
            {
                allTheatres = repository.findByDocType("theatre");
                Logger.info( "List of theatres found: " + allTheatres.toString() );
                for(Theatre theatre: allTheatres)
                {
                    Logger.info( "This theatre is: " + theatre.toString() );
                }
            }
            catch( NoClassDefFoundError | ClassNotFoundException e )
            {
                Logger.error( "Classpath: " + System.getProperty( "java.class.path" ) );
            }          
        }
        else
        {
            Logger.error( "TheatreRepository is NULL!" );
        }

        return ok(index.render("Your new application is ready."));
    }
}

以及 Spring 的 ApplicationContext:

package plugins.solr;

import play.Plugin;

import model.TheatreRepository;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import play.Logger;
import play.Play;
import play.api.Application;


public class SolrPlugin extends Plugin
{
    private TheatreRepository theatreRepository;    

    ApplicationContext ctx;

    public SolrPlugin(Application app)
    {

    }

    public TheatreRepository getTheatreRepository()
    {
        return theatreRepository;
    }

    @Override
    public void onStart()
    {
        super.onStart();
        Logger.info( "Solr plugin started" );

        ctx = new AnnotationConfigApplicationContext(SolrConfig.class);
        theatreRepository = ctx.getBean( TheatreRepository.class );
    }
}

这是基于 JavaConfig 的 spring 配置:

package plugins.solr;

import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.impl.HttpSolrServer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.solr.core.SolrOperations;
import org.springframework.data.solr.core.SolrTemplate;
import org.springframework.data.solr.repository.config.EnableSolrRepositories;
import org.springframework.data.solr.server.support.HttpSolrServerFactory;

import play.Play;

@ComponentScan
@Configuration
@EnableSolrRepositories(basePackages = { "model" })
public class SolrConfig
{
    public SolrConfig()
    {

    }

    @Bean
    public SolrServer solrServer()
    {
        HttpSolrServerFactory factory = new HttpSolrServerFactory( new HttpSolrServer( Play.application().configuration().getString( "ems.solr.url" ) ) );
        return factory.getSolrServer();
    }

    @Bean
    public SolrOperations solrTemplate()
    {
        return new SolrTemplate( this.solrServer() );
    }

}

因此,在重新加载浏览器窗口时会在运行时Application.index()调用,结果调用会theatreRepository.findByDocType("theatre");被执行。这是该调用的堆栈跟踪:

java.lang.NoClassDefFoundError: model/Theatre
at model.Theatre_Instantiator_982rn.newInstance(Unknown Source) ~[na:na]
at org.springframework.data.convert.BytecodeGeneratingEntityInstantiator$EntityInstantiatorAdapter.createInstance(BytecodeGeneratingEntityInstantiator.java:193) ~[spring-data-commons-1.10.0.RELEASE.jar:na]
at org.springframework.data.convert.BytecodeGeneratingEntityInstantiator.createInstance(BytecodeGeneratingEntityInstantiator.java:76) ~[spring-data-commons-1.10.0.RELEASE.jar:na]
at org.springframework.data.solr.core.convert.MappingSolrConverter.read(MappingSolrConverter.java:127) ~[spring-data-solr-1.4.0.RELEASE.jar:na]
at org.springframework.data.solr.core.convert.MappingSolrConverter.read(MappingSolrConverter.java:119) ~[spring-data-solr-1.4.0.RELEASE.jar:na]
Caused by: java.lang.ClassNotFoundException: model.Theatre
at java.lang.ClassLoader.findClass(ClassLoader.java:531) ~[na:1.7.0_80]
at java.lang.ClassLoader.loadClass(ClassLoader.java:425) ~[na:1.7.0_80]
at java.lang.ClassLoader.loadClass(ClassLoader.java:358) ~[na:1.7.0_80]
at model.Theatre_Instantiator_982rn.newInstance(Unknown Source) ~[na:na]
at org.springframework.data.convert.BytecodeGeneratingEntityInstantiator$EntityInstantiatorAdapter.createInstance(BytecodeGeneratingEntityInstantiator.java:193) ~[spring-data-commons-1.10.0.RELEASE.jar:na]

我注意到的是model.Theatre类文件在播放框架类加载器中,但不在系统类加载器中。但是,这似乎不是问题,因为当 springTheatreRespoitory需要实例化该类的实例时,它能够找到该类文件。我认为一定有一些简单的事情我做错了,但是在尝试了一些事情并进行了研究之后,我仍然不知所措。我确实找到了以下帖子,但它似乎不相关,因为它引用了 spring-data-mongodb 版本之间的差异。

MongoDB NoClassDefFoundError

另外,我刚刚尝试在 spring 应用程序上下文中使用 play frameworks 类加载器,方法是在SolrPlugin.onStart()

ctx = new AnnotationConfigApplicationContext(SolrConfig.class);
((AnnotationConfigApplicationContext)ctx).setClassLoader( Play.application().classloader() );

这导致了相同的NoClassDefFoundError堆栈跟踪。在设置类加载器之后,我还尝试在同一个函数中进行查询,并再次收到相同的错误。

4

1 回答 1

0

一种解决方法是强制恢复到基于反射的 1.7.0.RELEASE 之前的实例化策略ReflectionEntityInstantiatorMappingMongoConverter例如:

mappingConverter.setInstantiators(
    new EntityInstantiators(ReflectionEntityInstantiator.INSTANCE));
于 2015-07-17T10:41:16.527 回答