cqengine compare by datetime - java

I'm trying to find a list of objects that are after a certain DateTime. In order to do so, I've created the following query:
return foos.retrieve(QueryFactory.equal(EXPIRY_INDEX, new DateTime()));
I then created the following index:
public static final Attribute<Foo, DateTime> EXPIRY_INDEX = new SimpleAttribute<Foo, DateTime>() {
#Override
public DateTime getValue(Foo foo, QueryOptions queryOptions) {
return foo.getEXPIRY();
}
};
So far all good, except, the equal(...) method will invoke DateTime.equals(...) as far as I know which will ultimately return false all the time. What I need is a way to call DateTime.isAfterNow(...) or DateTime.isAfter(...).
How can I find all elements in a collection that have a DateTime after right now?

If I understand correctly, you should use a greaterThan() query instead of an equals() query.
These will rely on Comparable.compareTo(), instead of Object.equals(). So it should work if your DateTime object implements the Comparable interface properly.

Related

Convert hashmap to string

I am working on a legacy database where modifying the table schema is not an option. Most records are unique but there are some duplicate entries. For that reason I have modified the RecordRepository.java interface to perform a #Query with map(). Otherwise JPA will return the same data if it thinks it's the same record.
RecordRepository.java:
#Query("select new map(field1 as field1, field2 as field2) from Record where year = ?1")
List<Record> findByYear(String year);
RecordController.java:
#RestController
public class RecordController {
#Autowired
private RecordRepository recordRepository;
#RequestMapping(value = "/record/{year}", method = RequestMethod.GET)
public List<Record> recordByYear(#PathVariable("year") String year) {
List<Record> l = recordRepository.findByYear(year);
System.out.println(l.getClass());
System.out.println(l.get(1967));
return l;
}
}
The output from getClass() is class java.util.ArrayList. Printing item 1967 from the ArrayList is {field1=2018-01-15, field2=201801}.
But when trying to get the string-value of field1 using String tmp_r = l.get(1967).getField1() I get the error java.util.HashMap cannot be cast to Record.
I have tried various suggestions from SO. My head is spinning, I must be overlooking something simple explanation to this.
Regards
Claus
Well l.getClass() is an ArrayList, but that doesn't mean that all its elements are Record-s (maybe casts were done somewhere else).
When you call l.get(1967) the resulting item is an HashMap (right?), so maybe you can check the actual type of the expression l.get(1967) first.
If the map is indexed by Strings, then String tmp_r = l.get(1967).get("field1") will print your field.
Danieles answer, and STaefi's comment, led me in the rigth direction. The solution ended up being quite simple. My error can be attributed to the facts it's been a while I worked with this. I changed the return type in the interface from List to List.
RecordRepository.java:
List<HashMap<String, Record>> findByYear(String year);
RecordController:
List<HashMap<String, Record>> l = recordRepository.findByYear(year);
System.out.println(l.get(1967).get("field1"));
will give me the value field1 has.

Mockito when checking for specific object property value

I have the following in a working test:
when(client.callApi(anyString(), isA(Office.class))).thenReturn(responseOne);
Note that client is a Mock of class Client.
I want to change "isA(Office.class)" to tell it to match where the "id" property of an Office instance is "123L". How can I specify that I want a specific argument value in the method of a mocked object?
Edit: Not a duplicate because I'm trying to use it on a "when" and the linked question (and other resources I've found) are using ArgumentCaptor and ArgumentMatcher on "verify" and "assert". I'm thinking I can't actually do what I'm trying and will try out another way. Of course, I'm willing to be shown otherwise.
Reopening as requested, but the solution (use an ArgumentMatcher) is identical to the one in the linked answer. Naturally, you can't use an ArgumentCaptor when stubbing, but everything else is the same.
class OfficeWithId implements ArgumentMatcher<Office> {
long id;
OfficeWithId(long id) {
this.id = id;
}
#Override public boolean matches(Office office) {
return office.id == id;
}
#Override public String toString() {
return "[Office with id " + id + "]";
}
}
when(client.callApi(anyString(), argThat(new IsOfficeWithId(123L)))
.thenReturn(responseOne);
Because ArgumentMatcher has a single method, you can even make it a lambda in Java 8:
when(client.callApi(anyString(), argThat(office -> office.id == 123L))
.thenReturn(responseOne);
If you're already using Hamcrest, you can adapt a Hamcrest matcher using MockitoHamcrest.argThat, or use the built-in hasProperty:
when(client.callApi(
anyString(),
MockitoHamcrest.argThat(
hasProperty("id", equalTo(123L)))))
.thenReturn(responseOne);
I ended up going with "eq". This was ok in this case because the objects are pretty simple. First I created an object that is the same as what I expect to get back.
Office officeExpected = new Office();
officeExpected.setId(22L);
Then my 'when' statement becomes:
when(client.callApi(anyString(), eq(officeExpected))).thenReturn(responseOne);
This allows me to have better checking than "isA(Office.class)".
adding an answer for anyone with a more complex object.
answer from OP uses eq which works for simple objects.
However, I had a more complex object with many more fields. Its quite painful to create Mock object and fill in all the fields
public class CreateTenantRequest {
#NotBlank private String id;
#NotBlank private String a;
#NotBlank private String b;
...
...
}
I was able to use refEq to achieve the same thing without setting a value of each field.
Office officeExpected = new Office();
officeExpected.setId(22L);
verify(demoMock, Mockito.atLeastOnce()).foobarMethod(refEq(officeExpected, "a", "b"));

How would you make it generic?

This following code works properly, but I wanted it to have in generic style.
I tried to write it in a generic way, but I had some problems.
I have a method that is to get some data from two collections from MongoDB.
I use MongoOperations from package org.springframework.data.mongodb.core to handle MongoDB operations. The method find which I am calling, needs parameters: query, and a class of which the Mongo Collection is made of. Classes EvaluationWork and ArchivalWork implement an interface WorkContainer.
What I'd like to do is to make use of that T generic parameter, which is upper bounded by WorkContainer, by make generic the call of find method, instead of EvaluationWork.class and ArchivalWork.class if possible. And I am also curious whether is possible to have the function convertToWorkWithId generic and the possibility to call it in the same way as now, without casting (.map(w->convertToWorkWithId((T)w))) ?
public abstract class AbstractWorkMongoDao<T extends WorkContainer> {
protected WorkWithId convertToWorkWithId(WorkContainer evaluationWork) {
return evaluationWork.getWorkWithId();
}
/* there is some code here */
public List<WorkWithId> getByDate(String institutionId, String startDate, String endDate, boolean repository) {
Query query = buildSearchQuery(institutionId, startDate, endDate);
List<WorkWithId> workWithIds = mongoOperations.find(query, EvaluationWork.class)
.stream()
.map(this::convertToWorkWithId)
.collect(Collectors.toList());
if(repository){
workWithIds.addAll(mongoOperations.find(query, ArchivalWork.class)
.stream()
.map(this::convertToWorkWithId)
.collect(Collectors.toList())
);
}
return workWithIds;
}
}

How do I use a comparator (for a binary search) to compare a DateTime to a DateTime field in an object?

I want to compare inputted dates to a sorted list of holidays objects using a binary search. The holiday objects consist of a string with the name and a jodatime Datetime. So I am comparing the same types but one is part of an object and the other is not.
I have:
public class DateTimeComparator implements Comparator<DateTime> {
public int compare(DateTime userDate, DateTime listHoliday) {
if (userDate.equals(Holidays.getAllHolidays().date)) {
return 1;
}
else {
return 0;
}
}
}
Eclipse's feedback is that date can't be resolved. How can I correctly point to the date field of my Holiday list?
Edit: So if I don't need a comparator (suggested to me in another question), how do I structure my binary search? So far I have:
public static boolean isHoliday(List<Holiday> holidayList, DateTime date) {
if(Collections.binarySearch(holidayList.date, date)) {
return true;
}
return false;
}
You don't need to write a Comparator for this, DateTimes are already inherently Comparable. Also, referencing the date field for a LIST is non-sensical; its the ELEMENTS of the list with have that field, not the list itself.
You want to use Collections.binarySearch instead, and handle the output yourself.
I solved this by creating a new holiday and comparing two holiday objects to each other with a comparator that looks at the DateTime field.

MyBatis SelectList Output CopyOnWriteArrayList

Please be patient with the newbie question as I'm trying to learn MyBatis and java at the same time. I have an application in which I need to use threadsafe variables. Based on some research and my ideas of how the application will be used, I've settled on a CopyOnWriteArrayList over a Vector.
When I call a selectList from the mybatis sql session, is there any way to tell it to create an CopyOnWriteArrayList as its return rather than an ArrayList? Admittedly, my code to configure this is two lines instead of one, but something in me says that there's got to be a better way and/or I'm not the first one to have encountered this.
List<Team> teams = session.selectList("getTeamsByGameID", gameID);
List<Team> arrayListReturn = new CopyOnWriteArrayList<Team>(teams);
return arrayListReturn;
Thanks in advance,
I know of two ways to handle this.
Option 1: Use a Mapper class and specify the type of List to return there.
Define a Mapper interface:
public interface TeamMapper {
CopyOnWriteArrayList<Team> getTeamsByGameID();
}
Your mapper xml file stays the same. The code to do the query changes to:
TeamMapper m = session.getMapper(TeamMapper.class);
List<Team> lt = m.getTeamsByGameID();
System.out.println(lt.getClass());
//=> prints out "class java.util.concurrent.CopyOnWriteArrayList"
Option 2: Create a ResultHandler and pass that into the session.select() method.
Here you use the ResultHandler interface. That interface requires you to override one method, handleResult, which is given each result that comes back from the database as the query is in progress.
In your case, your ResultHandler would look something like this:
public class TeamResultHandler implements ResultHandler {
private List<Team> teams = new CopyOnWriteArrayList<Team>();
#Override
public void handleResult(ResultContext rc) {
countries.add((Team) rc.getResultObject());
}
// provide a getter so you can retrieve it when finished
public List<Team> getTeamList() {
return teams;
}
}
Instead of using selectList as you do above, you would now use the session.select(String, ResultHandler), like so:
TeamResultHandler rh = new TeamResultHandler();
session.select("getTeamsByGameID", rh);
List<Team> lt = rh.getTeamList();
return lt;
This solution is more verbose than your solution (requires an extra class and three lines in your query code, rather than 2), but it only creates one List, rather than two, so you'll have to decide which fits your needs best.
In addition, ResultHandlers can be useful for additional things - making sure results are sorted in a certain way or filtered or something else, in case you need that.

Categories

Resources