How do I write this J Unit test properly? It fails even though the code works. What am I missing? - angularjs

This is my first attempt at unit testing. The project is AngularJS/JavaEE. The REST calls are coded in Java. The method I am attempting to test returns emails from a GMail inbox. The emails return ok in JSON format and Google console confirms that a status 200 has been returned, however when I test if JSON is returned along with a status 200, it fails on both counts.
Here is the REST class:
#GET
#Path("/get")
#Produces(MediaType.APPLICATION_JSON)
public Response getInbox(#Context HttpServletRequest req)
throws ServletException, IOException, JSONException {
HttpSession session = req.getSession();
Credential credential = (Credential) session.getAttribute("credential");
Gmail service = new Gmail.Builder(HTTP_TRANSPORT, JSON_FACTORY,
credential).setApplicationName("Senior Mail").build();
ArrayList<String> ids = new ArrayList<String>();
ids.add("INBOX");
JSONObject ticketDetails = new JSONObject();
ListMessagesResponse openMessages = service.users().messages()
.list("me").setLabelIds(ids).setMaxResults(new Long(maxEmails)).execute();
List<com.google.api.services.gmail.model.Message> messages = openMessages
.getMessages();
JSONArray openTickets = new JSONArray();
if (messages != null) {
for (com.google.api.services.gmail.model.Message message : messages) {
openTickets.add(getBareGmailMessageDetails(message.getId(),
credential));
}
ticketDetails.put("openTicketDetails", openTickets);
}
return Response.status(200).entity("" + ticketDetails.toJSONString()).build();
}
Here is the test using RestAssured:
import static com.jayway.restassured.RestAssured.expect;
import org.junit.Before;
import org.junit.Test;
import com.jayway.restassured.RestAssured;
import com.jayway.restassured.http.ContentType;
public class InboxTest {
#Before
public void setUp(){
RestAssured.basePath = "http://localhost:8080/resources";
}
#Test
public void testGetProducts(){
expect().statusCode(200).contentType(ContentType.JSON).when()
.get("/inbox/get");
}
}
And here is the test result:
java.lang.AssertionError: 2 expectations failed.
Expected status code <200> doesn't match actual status code <400>.
Expected content-type "JSON" doesn't match actual content-type "".
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
at org.codehaus.groovy.reflection.CachedConstructor.invoke(CachedConstructor.java:77)
at org.codehaus.groovy.reflection.CachedConstructor.doConstructorInvoke(CachedConstructor.java:71)
at org.codehaus.groovy.runtime.callsite.ConstructorSite$ConstructorSiteNoUnwrap.callConstructor(ConstructorSite.java:81)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallConstructor(CallSiteArray.java:57)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:182)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:190)
at com.jayway.restassured.internal.ResponseSpecificationImpl$HamcrestAssertionClosure.validate(ResponseSpecificationImpl.groovy:436)
at com.jayway.restassured.internal.ResponseSpecificationImpl$HamcrestAssertionClosure$validate$1.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at com.jayway.restassured.internal.RequestSpecificationImpl.invokeFilterChain(RequestSpecificationImpl.groovy:774)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1085)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:909)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:730)
at com.jayway.restassured.internal.RequestSpecificationImpl.invokeMethod(RequestSpecificationImpl.groovy)
at org.codehaus.groovy.runtime.callsite.PogoInterceptableSite.call(PogoInterceptableSite.java:45)
at org.codehaus.groovy.runtime.callsite.PogoInterceptableSite.callCurrent(PogoInterceptableSite.java:55)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:49)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:133)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:149)
at com.jayway.restassured.internal.RequestSpecificationImpl.applyPathParamsAndSendRequest(RequestSpecificationImpl.groovy:1230)
at com.jayway.restassured.internal.RequestSpecificationImpl.this$2$applyPathParamsAndSendRequest(RequestSpecificationImpl.groovy)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1085)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:909)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:730)
at com.jayway.restassured.internal.RequestSpecificationImpl.invokeMethod(RequestSpecificationImpl.groovy)
at org.codehaus.groovy.runtime.callsite.PogoInterceptableSite.call(PogoInterceptableSite.java:45)
at org.codehaus.groovy.runtime.callsite.PogoInterceptableSite.callCurrent(PogoInterceptableSite.java:55)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:49)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:133)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:149)
at com.jayway.restassured.internal.RequestSpecificationImpl.get(RequestSpecificationImpl.groovy:136)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1085)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:909)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:730)
at com.jayway.restassured.internal.RequestSpecificationImpl.invokeMethod(RequestSpecificationImpl.groovy)
at org.codehaus.groovy.runtime.callsite.PogoInterceptableSite.call(PogoInterceptableSite.java:45)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120)
at com.jayway.restassured.internal.ResponseSpecificationImpl.get(ResponseSpecificationImpl.groovy:241)
at com.mail.senior.test.InboxTest.testGetProducts(InboxTest.java:22)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

Not actually having used this rest-testing-framework myself, looking at the examples found on their github repo I would try adding an "and()" between the two separate checks:
expect().statusCode(200).and().contentType(ContentType.JSON).when().get("/inbox/get")

Related

RestEasy client does not use correct encoding

I'm using RestEasy as a client to read news from a service.
ResteasyClient listClient = new ResteasyClientBuilder().build();
ResteasyWebTarget listTarget = listClient.target("https://someservice.com/file.xml");
Response r = listTarget.request().get();
final HexMl feedList = r.readEntity(HexMl.class);
The service does not return an encoding or media type in the response header, only an encoding in the xml itself
<?xml version="1.0" encoding="windows-1252"?>
RestEasy does not seem to evaluate this so I get an exception:
javax.ws.rs.ProcessingException: org.jboss.resteasy.plugins.providers.jaxb.JAXBUnmarshalException: javax.xml.bind.UnmarshalException
- with linked exception:
[org.xml.sax.SAXParseException; lineNumber: 116; columnNumber: 30; Invalid byte 2 of 3-byte UTF-8 sequence.]
at org.jboss.resteasy.client.jaxrs.internal.ClientResponse.readFrom(ClientResponse.java:300)
at org.jboss.resteasy.client.jaxrs.internal.ClientResponse.readEntity(ClientResponse.java:196)
at org.jboss.resteasy.specimpl.BuiltResponse.readEntity(BuiltResponse.java:218)
at com.roche.services.NewsImportService.importFeed(NewsImportService.java:72)
at com.roche.commands.NewsImportCommand.execute(NewsImportCommand.java:26)
at com.roche.commands.NewsImportCommand$execute.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:110)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:122)
at Script1.run(Script1.groovy:4)
at info.magnolia.module.groovy.console.MgnlGroovyConsole$1.call(MgnlGroovyConsole.java:154)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: org.jboss.resteasy.plugins.providers.jaxb.JAXBUnmarshalException: javax.xml.bind.UnmarshalException
Is there a way to overwrite the encoding RestEasy uses or intercept the response before the entity is read?
I tried
Response r = listTarget.request().accept(APPLICATION_XML + ";charset=windows-1252").get();
and
Response r = listTarget.request(APPLICATION_XML + ";charset=windows-1252").get();
and
#Consumes(APPLICATION_XML + ";charset=windows-1252")
public class HexMl { ... }
without success. The XML itself seems to be correctly encoded in windows-1252.
For now I'm using a ReaderInterceptor, but this doesn't seem right. So I'd still be glad about better suggestions.
ResteasyClientBuilder clientBuilder = new ResteasyClientBuilder();
ResteasyProviderFactory providerFactory = new ResteasyProviderFactory();
RegisterBuiltin.register( providerFactory );
providerFactory.getClientReaderInterceptorRegistry().registerSingleton( new ReaderInterceptor() {
#Override
public Object aroundReadFrom(ReaderInterceptorContext context) throws IOException, WebApplicationException {
InputStream is = context.getInputStream();
String responseBody = IOUtils.toString( is , "windows-1252");
LOGGER.debug( "received response:\n{}\n\n", responseBody );
context.setInputStream( new ByteArrayInputStream( responseBody.getBytes() ) );
return context.proceed();
}
} );
clientBuilder.providerFactory( providerFactory );
Then I use this clientBuilder to create my client.

spring-data-mongodb bulkOps cant not serialize enum

I an enum field in my model,when I use find method to query some data with this field as condition, it return as wanted.
but, when I use bulkOps and excute an upsert operation,it tells me:
can't serialize class com.timanetworks.tpc.vehicle.alarm.domain.enums.FaultType
I am try to add name() method of enum to resolve this problem, and it's success! But I still can not understand why? does any one know?
my model is like this:
#Document(collection = "FaultSnapshot")
#TypeAlias("faultSnapshot")
public class FaultSnapshot extends BaseDocument {
private FaultType type;
private String vin;
private Integer faultLevel;
private Boolean isFault;
private Date time;
...setters and getters...
and FaultType is an enum:
public enum FaultType {
FAULT_EMS,
....
}
and this is find code:
Query query = new Query();
if (type != null) {
query.addCriteria(where("type").is(type));
}
Pageable pageable = new PageRequest(pageIndex - 1, pageSize);
Sort sort = new Sort(Sort.Direction.DESC, "time");
List<FaultHistory> histories = template.find(query.with(pageable).with(sort),
FaultHistory.class);
return new Page<>(count, histories);
this is bulkOps code:
public void upsertSnapshot(Collection<FaultSnapshot> snapshots) {
BulkOperations bulk = template.bulkOps(BulkOperations.BulkMode.UNORDERED, FaultSnapshot.class);
for (FaultSnapshot snapshot : snapshots) {
Query query = new Query();
query.addCriteria(where("vin").is(snapshot.getVin()));
query.addCriteria(where("type").is(snapshot.getType().name()));
Update update = new Update()
.set("isFault", snapshot.getFault())
.set("faultLevel", snapshot.getFaultLevel())
.set("time", snapshot.getTime())
.set("vin", snapshot.getVin())
.set("type", snapshot.getType().name());
bulk.upsert(query, update);
}
bulk.execute();
}
finally,this is the error stack:
Exception in thread "Thread-11" java.lang.IllegalArgumentException: can't serialize class com.timanetworks.tpc.vehicle.alarm.domain.enums.FaultType
at org.bson.BasicBSONEncoder._putObjectField(BasicBSONEncoder.java:299)
at org.bson.BasicBSONEncoder.putObject(BasicBSONEncoder.java:194)
at org.bson.BasicBSONEncoder._putObjectField(BasicBSONEncoder.java:255)
at org.bson.BasicBSONEncoder.putObject(BasicBSONEncoder.java:194)
at org.bson.BasicBSONEncoder.putObject(BasicBSONEncoder.java:136)
at com.mongodb.DefaultDBEncoder.writeObject(DefaultDBEncoder.java:36)
at com.mongodb.OutMessage.putObject(OutMessage.java:289)
at com.mongodb.OutMessage.writeUpdate(OutMessage.java:180)
at com.mongodb.OutMessage.update(OutMessage.java:60)
at com.mongodb.DBCollectionImpl$Run$1.executeWriteProtocol(DBCollectionImpl.java:908)
at com.mongodb.DBCollectionImpl$Run$RunExecutor.executeWriteProtocol(DBCollectionImpl.java:1025)
at com.mongodb.DBCollectionImpl$Run$RunExecutor.execute(DBCollectionImpl.java:1016)
at com.mongodb.DBCollectionImpl$Run.executeUpdates(DBCollectionImpl.java:917)
at com.mongodb.DBCollectionImpl$Run.execute(DBCollectionImpl.java:859)
at com.mongodb.DBCollectionImpl.executeBulkWriteOperation(DBCollectionImpl.java:169)
at com.mongodb.DBCollection.executeBulkWriteOperation(DBCollection.java:1904)
at com.mongodb.DBCollection.executeBulkWriteOperation(DBCollection.java:1899)
at com.mongodb.BulkWriteOperation.execute(BulkWriteOperation.java:116)
at org.springframework.data.mongodb.core.DefaultBulkOperations.execute(DefaultBulkOperations.java:276)
at com.timanetworks.tpc.vehicle.alarm.dao.FaultSnapshotRepositoryImpl.***upsertSnapshot***(FaultSnapshotRepositoryImpl.java:39)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
This is actually a bug (DATAMONGO-1678) in Spring Data MongoDB. It has already been fixed for 1.9.12, 1.10.5 and 2.0.0.RC1.
At the time of writing none of the mentioned versions has been released.

EasyMock: AssertionError - Unexpected method call: with multiple expecations with multiple mocking objects

I am new to EasyMock and implementing JUnits in my project.
Below is my Test class, by looking the code you can understand what I am doing here. I am using EasyMock 3.4.
in short:
I am writing a Junit for my actual method FmrTradeConsumerImpl.onTODEvent(TodEvents todEvents).
myTestClass:
#RunWith(EasyMockRunner.class)
public class FmrTradeConsumerImplTest extends EasyMockSupport {
#TestSubject
private FmrTradeConsumerImpl fmrTradeConsumer = new FmrTradeConsumerImpl();
#Mock
private TradeService tradeService;
#Mock
private TradeIvTypeValidator tradeValid;
#Mock
private TodEvents todEvents;
private List<TradeDetails> tradesList;
private SecurityTradeExecution tradeEx;
private List<SecurityTradeExecution> securityTradeEx;
#Before
public void init() {
tradeService = niceMock(TradeService.class);
todEvents = niceMock(TodEvents.class);
securityTradeEx = new ArrayList<>();
tradesList = new ArrayList<>();
tradeEx = new SecurityTradeExecution();
tradeValid = niceMock(TradeIvTypeValidator.class);
resetAll();
}
#Test
public void onTODEvent() {
tradeEx.setFundNumber(Long.valueOf("2016"));
tradeEx.setSourceSystemCd("AIM");
tradeEx.setIvType("Test");
securityTradeEx.add(tradeEx);
expect(todEvents.getSecurityTradeExcecutions()).andReturn(securityTradeEx);
expect(tradeValid.isValidIvType("Test")).andReturn(true);
tradeService.saveTradeRecordsListAsBatch(tradesList);
expectLastCall().andVoid();
replayAll();
fmrTradeConsumer.onTODEvent(todEvents);
}
}
And I am getting below errors:
java.lang.AssertionError:
Unexpected method call TradeIvTypeValidator.isValidIvType("Test"):
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:44)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:94)
at org.easymock.internal.ClassProxyFactory$MockMethodInterceptor.intercept(ClassProxyFactory.java:97)
at com.fmr.ftg.es.mas.tod.client.TradeIvTypeValidator$$EnhancerByCGLIB$$311c4357.isValidIvType(<generated>)
at com.fmr.ftg.es.mas.tod.client.impl.FmrTradeConsumerImpl.isValidTrade(FmrTradeConsumerImpl.java:120)
at com.fmr.ftg.es.mas.tod.client.impl.FmrTradeConsumerImpl.onTODEvent(FmrTradeConsumerImpl.java:67)
at com.fmr.ftg.es.mas.tod.client.impl.FmrTradeConsumerImplTest.onTODEvent(FmrTradeConsumerImplTest.java:78)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
Please provide your suggestions,
Thank you much in advance.
Instead of using "#Mock" annotation for "private TradeIvTypeValidator tradeValid;", use "#NiceMock".
Here NiceMock provides default implementations and if you are using "#Mock" its upto for developer to do the same
Why are you resetting all the mocks after creation? Can you remove that line and try if it works

Lucene indexWriter update does not affect Solr search

I implement a small code for the purpose of extracting some keywords out of Lucene index. I did implement that using search component. My problem is when I tried to update Lucene IndexWriter, Solr index which is placed on top of that, does not affect. As you can see I did the commit part.
BooleanQuery query = new BooleanQuery();
for (String fieldName : keywordSourceFields) {
TermQuery termQuery = new TermQuery(new Term(fieldName,"N/A"));
query.add(termQuery, Occur.MUST_NOT);
}
TermQuery termQuery=new TermQuery(new Term(keywordField, "N/A"));
query.add(termQuery, Occur.MUST);
try {
//Query q= new QueryParser(keywordField, new StandardAnalyzer()).parse(query.toString());
TopDocs results = searcher.search(query,
maxNumDocs);
ScoreDoc[] hits = results.scoreDocs;
IndexWriter writer = getLuceneIndexWriter(searcher.getPath());
for (int i = 0; i < hits.length; i++) {
Document document = searcher.doc(hits[i].doc);
List<String> keywords = keyword.getKeywords(hits[i].doc);
if(keywords.size()>0) document.removeFields(keywordField);
for (String word : keywords) {
document.add(new StringField(keywordField, word, Field.Store.YES));
}
String uniqueKey = searcher.getSchema().getUniqueKeyField().getName();
writer.updateDocument(new Term(uniqueKey, document.get(uniqueKey)),
document);
}
writer.commit();
writer.forceMerge(1);
writer.close();
} catch (IOException | SyntaxError e) {
throw new RuntimeException();
}
private IndexWriter getLuceneIndexWriter(String indexPath) throws IOException {
FSDirectory directory = FSDirectory.open(new File(indexPath).toPath());
Analyzer analyzer = new StandardAnalyzer();
IndexWriterConfig iwc = new IndexWriterConfig(analyzer);
return new IndexWriter(directory, iwc);
}
Please help me through solving this problem.
Update:
I did some investigation and found out that the retrieving part of documents works fine while Solr did not restarted. But the searching part of documents did not work. After I restarted Solr it seems that the core corrupted and failed to start! Here is the corresponding log:
org.apache.solr.common.SolrException: Error opening new searcher
at org.apache.solr.core.SolrCore.<init>(SolrCore.java:896)
at org.apache.solr.core.SolrCore.<init>(SolrCore.java:662)
at org.apache.solr.core.CoreContainer.create(CoreContainer.java:513)
at org.apache.solr.core.CoreContainer$1.call(CoreContainer.java:278)
at org.apache.solr.core.CoreContainer$1.call(CoreContainer.java:272)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
at java.util.concurrent.FutureTask.run(FutureTask.java:166)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:722)
Caused by: org.apache.solr.common.SolrException: Error opening new searcher
at org.apache.solr.core.SolrCore.openNewSearcher(SolrCore.java:1604)
at org.apache.solr.core.SolrCore.getSearcher(SolrCore.java:1716)
at org.apache.solr.core.SolrCore.<init>(SolrCore.java:868)
... 9 more
Caused by: org.apache.lucene.index.IndexNotFoundException: no segments* file found in NRTCachingDirectory(MMapDirectory#C:\Users\Ali\workspace\lucene_solr_5_0_0\solr\server\solr\document\data\index lockFactory=org.apache.lucene.store.SimpleFSLockFactory#3bf76891; maxCacheMB=48.0 maxMergeSizeMB=4.0): files: [_2_Lucene50_0.doc, write.lock, _2_Lucene50_0.pos, _2.nvd, _2.fdt, _2_Lucene50_0.tim]
at org.apache.lucene.index.IndexWriter.<init>(IndexWriter.java:821)
at org.apache.solr.update.SolrIndexWriter.<init>(SolrIndexWriter.java:78)
at org.apache.solr.update.SolrIndexWriter.create(SolrIndexWriter.java:65)
at org.apache.solr.update.DefaultSolrCoreState.createMainIndexWriter(DefaultSolrCoreState.java:272)
at org.apache.solr.update.DefaultSolrCoreState.getIndexWriter(DefaultSolrCoreState.java:115)
at org.apache.solr.core.SolrCore.openNewSearcher(SolrCore.java:1573)
... 11 more
4/7/2015, 6:53:26 PM
ERROR
SolrIndexWriter
SolrIndexWriter was not closed prior to finalize(),​ indicates a bug -- POSSIBLE RESOURCE LEAK!!!
4/7/2015, 6:53:26 PM
ERROR
SolrIndexWriter
Error closing IndexWriter
java.lang.NullPointerException
at org.apache.lucene.index.IndexWriter.doFlush(IndexWriter.java:2959)
at org.apache.lucene.index.IndexWriter.flush(IndexWriter.java:2927)
at org.apache.lucene.index.IndexWriter.shutdown(IndexWriter.java:965)
at org.apache.lucene.index.IndexWriter.close(IndexWriter.java:1010)
at org.apache.solr.update.SolrIndexWriter.close(SolrIndexWriter.java:130)
at org.apache.solr.update.SolrIndexWriter.finalize(SolrIndexWriter.java:183)
at java.lang.ref.Finalizer.invokeFinalizeMethod(Native Method)
at java.lang.ref.Finalizer.runFinalizer(Finalizer.java:101)
at java.lang.ref.Finalizer.access$100(Finalizer.java:32)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:190)
There for my guess would be problem with indexing the keywordField and also problem related to closing the IndexWriter.

Does Spring Expression Language support IN operator?

Does Spring Expression Language support IN operator? Similar to SQL IN clause.
public class Security {
private secTyp1;
public Security (String aSecTyp1) {
secTyp1 = aSecTyp1;
}
}
Security security = new Security("BOND");
StandardEvaluationContext context = new StandardEvaluationContext(security);
ExpressionParser parser = new SpelExpressionParser();
// This should return true
boolean result = parser.parseExpression("secTyp1 **IN** {'BOND','SWPI'}").getValue(context, Boolean.class);
// This should return false
result = parser.parseExpression("secTyp1 **IN** {'FUT','SWPI'}").getValue(context, Boolean.class);
I get the following exception
org.springframework.expression.spel.SpelParseException: EL1041E:(pos 8): After parsing a valid expression, there is still more data in the expression: 'IN'
at org.springframework.expression.spel.standard.InternalSpelExpressionParser.doParseExpression(InternalSpelExpressionParser.java:118)
at org.springframework.expression.spel.standard.SpelExpressionParser.doParseExpression(SpelExpressionParser.java:56)
at org.springframework.expression.spel.standard.SpelExpressionParser.doParseExpression(SpelExpressionParser.java:1)
at org.springframework.expression.common.TemplateAwareExpressionParser.parseExpression(TemplateAwareExpressionParser.java:66)
at org.springframework.expression.common.TemplateAwareExpressionParser.parseExpression(TemplateAwareExpressionParser.java:56)
at com.rules.AssignableSecurityRule.evaluateInCondition(AssignableSecurityRule.java:48)
at com.rules.AssignableSecurityRuleTest.testINCondition(AssignableSecurityRuleTest.java:43)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
It does not support the IN operator because you do not need it. You can use the Method invokation feature instead.
So, invoking .contains(..) on a list will do what you want.
You can try those two solutions
#Test
public void solutionOneTest() {
final Security security = new Security("BOND");
final EvaluationContext context = new StandardEvaluationContext(security);
Boolean contains = PARSER.parseExpression("{'BOND','SWPI'}.contains(#root.secTyp1)").getValue(context, Boolean.class);
Assert.assertTrue(contains);
contains = PARSER.parseExpression("{'FUT','SWPI'}.contains(#root.secTyp1)").getValue(context, Boolean.class);
Assert.assertFalse(contains);
}
#Test
public void solutionTwoTest() {
final Security security = new Security("BOND");
final EvaluationContext context = new StandardEvaluationContext();
context.setVariable("sec", security);
Boolean contains = PARSER.parseExpression("{'BOND','SWPI'}.contains(#sec.secTyp1)").getValue(context, Boolean.class);
Assert.assertTrue(contains);
contains = PARSER.parseExpression("{'FUT','SWPI'}.contains(#sec.secTyp1)").getValue(context, Boolean.class);
Assert.assertFalse(contains);
}
In addition to calling methods directly as in micfra's answer, SpEL also supports some pretty powerful collection filtering expressions as well. Collection Selection allows you to filter out a sublist of matching values, when you could then test for size:
!{'BOND','SWPI'}.?[#this == 'BOND'].empty
Where this is really handy is filtering lists of complex objects:
!securities.?[secTyp1 == 'BOND'].empty

Resources