I have a hazelcast instance whose key is of type MyObject and value is an enum.
Let's say one of the attributes of MyObject class is date which is of type java.sql.Date.
class MyObject {
private Date date;
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date
}
}
public enum MyEnum {
TEST_ENUM;
}
Also I am using predicate to filter on the keys retrieve the enum value.
For ex:
EntryObject entryObject = new PredicateBuilder().getEntryObject();
PredicateBuiler predicateBuilder = entryObject.key.get(date).isNull;
This is how I am trying to add index:
IMap<MyObject, MyEnum> map = hazelcastInstance.getMap("test");
map.addIndex("date", true)
But as soon as this gets executed an exception is being thrown:
com.hazelcast.query.QueryException: java.lang.IllegalArgumentException: There is no suitable accessor for 'date' on class 'class com.main.constants.myEnum'
at com.hazelcast.query.impl.getters.ReflectionHelper.createGetter(ReflectionHelper.java:176)
at com.hazelcast.query.impl.getters.Extractors.instantiateGetter(Extractors.java:88)
at com.hazelcast.query.impl.getters.Extractors.getGetter(Extractors.java:73)
at com.hazelcast.query.impl.getters.Extractors.extract(Extractors.java:57)
at com.hazelcast.query.impl.QueryableEntry.extractAttributeValueFromTargetObject(QueryableEntry.java:156)
at com.hazelcast.query.impl.QueryableEntry.extractAttributeValue(QueryableEntry.java:82)
at com.hazelcast.query.impl.QueryableEntry.getAttributeValue(QueryableEntry.java:48)
at com.hazelcast.query.impl.QueryableEntry.getConverter(QueryableEntry.java:67)
at com.hazelcast.query.impl.IndexImpl.saveEntryIndex(IndexImpl.java:67)
at com.hazelcast.map.impl.operation.AddIndexOperation.run(AddIndexOperation.java:75)
I understand it's trying to find the index attribute in the value class
How do I get this thing working i.e. add the index on the Key rather than on the value.
While writing a test I actually found your problem :-)
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.IMap;
import com.hazelcast.query.EntryObject;
import com.hazelcast.query.PredicateBuilder;
import java.io.Serializable;
import java.sql.Date;
public class Test
{
public static void main(String[] args)
{
HazelcastInstance hz = Hazelcast.newHazelcastInstance();
IMap<MyObject, MyEnum> map = hz.getMap("test");
EntryObject entryObject = new PredicateBuilder().getEntryObject();
PredicateBuilder builder = entryObject.key().get("date").isNull();
map.addIndex("__key#date", true);
map.put(new MyObject(), MyEnum.TEST_ENUM);
}
public static class MyObject implements Serializable
{
private Date date;
public Date getDate()
{
return date;
}
public void setDate(Date date)
{
this.date = date;
}
}
public static enum MyEnum {
TEST_ENUM;
}
}
The trick is to create the index based on the map-key and not the value which is taken by default. You already did it in your query entryObject.key() but missed it on the index definition __key.date.
Related
I'm trying to create make a method, that returns a json-string filled with sample-data. I have created a data-constructor class but when I when I create a data-object and afterwards print it, it for some reason returns an empty json: "[]"?
What am I missing here? Why doesn't it return the data-object I just created?
Here is my main class:
public class SimulatedDevice {
public static void printObject(Object object) {
Gson gson = new GsonBuilder().setPrettyPrinting().create();
System.out.println(gson.toJson(object));
}
public static class TelemetryDataPoint {
public String CreateTelemetryDataPoint() {
ArrayList<Data.TrendData> trendData = new ArrayList<>();
trendData.add(new Data.TrendData("Building1", "2018-08-28T01:03:02.997301Z", 2, "occupants", "int"));
Data data = new Data("B1", "0", "0", trendData);
printObject(data);
String json = new Gson().toJson(data);
return json;
}
}
}
This is my data constructor:
package com.microsoft.docs.iothub.samples;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.sql.Time;
import java.util.ArrayList;
import java.util.List;
public class Data extends ArrayList {
String Building;
String Floor;
String Zone;
ArrayList<TrendData> Trend;
public Data(String Building, String Floor, String Zone, ArrayList<TrendData> Trend) {
this.Building = Building;
this.Floor = Floor;
this.Zone = Zone;
this.Trend = Trend;
}
public static class TrendData {
String PointId;
String Timestamp;
int Value;
String Type;
String Unit;
public TrendData(String PointId, String Timestamp, int Value, String Type, String Unit) {
this.PointId = PointId;
this.Timestamp = Timestamp;
this.Value = Value;
this.Type = Type;
this.Unit = Unit;
}
}
If you remove 'extends ArrayList' from Data declaration it will work fine. I have not debugged it enough to figure out why Gson does not like the base class being ArrayList.
Here is a possible explanation: Trouble with Gson serializing an ArrayList of POJO's
Can someone help me to store the current system date in cassandra date column in format yyyy-mm-dd using Java? I get exception while saving the java.sql.Date using MappingManager.
My sample program is:
Test.java
import com.datastax.driver.mapping.annotations.Table;
import java.sql.Date;
#Table(keyspace = "testing", name = "test")
public class Test {
private String uid;
private Date rece;
public String getUid() {
return uid;
}
public void setUid(String uid) {
this.uid = uid;
}
public Date getRece() {
return rece;
}
public void setRece(Date rece) {
this.rece = rece;
}
}
TestDao.java
Mapper mapper = new MappingManager(session).mapper(Test.class);
mapper.save(test);
Cassandra Schema :
CREATE TABLE tokenizer.test (
id text PRIMARY KEY,
testdate date
) ;
Either declare data type of rece to com.datastax.driver.core.LocalDate or Write a custom codec to encode java.sql.Date and register it to the cluster.
Custom codec Example :
import com.datastax.driver.core.LocalDate;
import com.datastax.driver.core.ProtocolVersion;
import com.datastax.driver.core.TypeCodec;
import com.datastax.driver.core.exceptions.InvalidTypeException;
import java.nio.ByteBuffer;
import java.sql.Date;
public class DateCodec extends TypeCodec<Date> {
private final TypeCodec<LocalDate> innerCodec;
public DateCodec(TypeCodec<LocalDate> codec, Class<Date> javaClass) {
super(codec.getCqlType(), javaClass);
innerCodec = codec;
}
#Override
public ByteBuffer serialize(Date value, ProtocolVersion protocolVersion) throws InvalidTypeException {
return innerCodec.serialize(LocalDate.fromMillisSinceEpoch(value.getTime()), protocolVersion);
}
#Override
public Date deserialize(ByteBuffer bytes, ProtocolVersion protocolVersion) throws InvalidTypeException {
return new Date(innerCodec.deserialize(bytes, protocolVersion).getMillisSinceEpoch());
}
#Override
public Date parse(String value) throws InvalidTypeException {
return new Date(innerCodec.parse(value).getMillisSinceEpoch());
}
#Override
public String format(Date value) throws InvalidTypeException {
return value.toString();
}
}
How to use it ?
Example :
CodecRegistry codecRegistry = new CodecRegistry();
codecRegistry.register(new DateCodec(TypeCodec.date(), Date.class));
try (Cluster cluster = Cluster.builder().withCodecRegistry(codecRegistry).addContactPoint("127.0.0.1").withCredentials("cassandra", "cassandra").build(); Session session = cluster.connect("test")) {
Mapper mapper = new MappingManager(session).mapper(Test.class);
mapper.save(test);
}
I had similar issues and As per Ashraful's answer, I have added below code in my model which resolved the issue.
Meta Data Model:
public class MetaData {
private String receive_date;
private String receive_hour;
**private com.datastax.driver.core.LocalDate error_date;**
}
In my service class, added below code.
final MetaData metaData = MetaData.builder()
.receive_date(row.getString("receive_date"))
.receive_hour(row.getString("receive_hour"))
.error_date(row.getDate("error_date"))
.build();
I have a class like this:
#Data
#NoArgsConstructor(force = true)
#AllArgsConstructor(staticName = "of")
public class BusinessPeriodDTO {
#DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
LocalDate startDate;
#DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
LocalDate endDate;
}
And I used this class inside another class, let's call it PurchaseOrder
#Entity
#Data
#NoArgsConstructor(access = AccessLevel.PROTECTED, force = true)
public class PurchaseOrder {
#EmbeddedId
PurchaseOrderID id;
#Embedded
BusinessPeriod rentalPeriod;
public static PurchaseOrder of(PurchaseOrderID id, BusinessPeriod period) {
PurchaseOrder po = new PurchaseOrder();
po.id = id;
po.rentalPeriod = period;
return po;
}
And I'm trying to populate a purchaseOrder record using jakson and this JSON:
{
"_class": "com.rentit.sales.domain.model.PurchaseOrder",
"id": 1,
"rentalPeriod": {
"startDate": "2016-10-10",
"endDate": "2016-12-12"
}
}
But I have faced with an error:
java.lang.RuntimeException: com.fasterxml.jackson.databind.JsonMappingException: Can not instantiate value of type [simple type, class java.time.LocalDate] from String value ('2016-10-10');
I am sure jakson and popularization works correctly.
Include in your pom.xml:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.9.6</version>
</dependency>
Then in your BusinessPeriodDTO.java import LocalDateDeserializer as follows:
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
And finally, always in your BusinessPeriodDTO.java file, annotate the interested dates like this:
#JsonDeserialize(using = LocalDateDeserializer.class)
LocalDate startDate;
#JsonDeserialize(using = LocalDateDeserializer.class)
LocalDate endDate;
Old question but I recently had to answer it for myself.
There are different solutions (as commented by rapasoft, see for example here).
The quick solution I used involves adding a setDate(String) method for deserialization.
It might not be the prettiest solution, but it works without updating other classes.
Below a runnable class to demonstrate:
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonFormat.Shape;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
/**
* Demonstrate Java 8 date/time (de)serialization for JSON with Jackson databind.
* Requires {#code com.fasterxml.jackson.core:jackson-databind:2.8.5}
* and {#code com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.8.5}
*/
public class JdateDto {
/** The pattern as specified by {#link java.text.SimpleDateFormat} */
public static final String ISO_LOCAL_DATE_PATTERN = "yyyy-MM-dd";
/* Used when serializing isoLocalDate. */
#JsonFormat(shape = Shape.STRING, pattern = ISO_LOCAL_DATE_PATTERN)
private LocalDate isoLocalDate;
public LocalDate getIsoLocalDate() {
return isoLocalDate;
}
/* Used when deserializing isoLocalDate. */
public void setIsoLocalDate(String date) {
setIsoLocalDate(LocalDate.parse(date, DateTimeFormatter.ISO_LOCAL_DATE));
}
public void setIsoLocalDate(LocalDate isoDate) {
this.isoLocalDate = isoDate;
}
public static void main(String[] args) {
try {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
JdateDto dto = new JdateDto();
dto.setIsoLocalDate(LocalDate.now());
String json = mapper.writeValueAsString(dto);
System.out.println(json);
JdateDto dto2 = mapper.readValue(json, JdateDto.class);
if (dto.getIsoLocalDate().equals(dto2.getIsoLocalDate())) {
System.out.println("Dates match.");
} else {
System.out.println("Dates do not match!");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Specifically in SQL server (and I'm assuming others), there is a datetimeoffset type that can store the timestamp with an offset other than GMT. (Looks like this "1998-01-01 15:00:00.0000000 +06:00")
But trying to persist a Calendar to the database automatically converts it to GMT (although I can't tell who's doing it JPA, Hibernate, or sqljdbc) so it looks like this "1998-01-01 9:00:00.0000000 +00:00"
Is there a way to prevent this for certain attributes?
Altough there might be other solutions using SQL databases, I always follow this approach:
In a data base or file I always store times in UTC, with no exception.
If the timezone has to be preserved, e.g for UI, then I store the UTC offset in an extra field.
This way I have the correct time, and if needded the time zone is preserved.
Found a way to do it
package testers.jpa.beans;
import java.io.Serializable;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.Transient;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
#Entity
#Table(name = "dbo.tester")
//Ignore the actual calendar object here because the jsonner strips the timezone info from it
#JsonIgnoreProperties(value = { "date" })
#NamedQuery(name = "NameAndOffset.purge", query = "DELETE FROM NameAndOffset")
public class NameAndOffset implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private Calendar date;
public NameAndOffset() {
}
public NameAndOffset(String name, Calendar date) {
this.name = name;
this.date = date;
}
#Id
#Basic
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
* Return a string representation of the {#link NameAndOffset#date} object.<br/>
* This will be used by JPA and the Jsonner to prevent losing the timezone
* information<br/>
* <br/>
* For this to work properly you must tell both the Json mapper and JPA to
* ignore anything else that relates to the {#link NameAndOffset#date} field
*
* #return A String representation of the {#link NameAndOffset#date} field,
* formatted for SQL Server's datetimeoffset data type
*/
#Basic
#Column(name = "date")
public String getDateTimeOffset() {
return new OffsetDateFormat().formatCalendar(date);
}
public void setDateTimeOffset(String date) throws ParseException {
this.date = new OffsetDateFormat().parseCalendar(date);
}
//Ignore the actual calendar object here because JPA strips the timezone info from it
#Transient
public Calendar getDate() {
return date;
}
public void setDate(Calendar date) throws ParseException {
this.date = date;
}
class OffsetDateFormat extends SimpleDateFormat {
private static final long serialVersionUID = 1L;
private static final String OFFSET_FORMAT = "yyyy-MM-dd HH:mm:ss.S Z";
public OffsetDateFormat() {
super(OFFSET_FORMAT);
}
public Calendar parseCalendar(String source) throws ParseException {
//pull out the colon in the offset
int timeZoneColon = source.lastIndexOf(":");
String nocolon = source.substring(0, timeZoneColon) + source.substring(timeZoneColon + 1);
Calendar cal = Calendar.getInstance();
cal.setTime(parse(nocolon));
//after parsing, the timezone of this DateFormatter changes to whatever was represented in the string
//make sure the new calendar reflects this
cal.setTimeZone(getTimeZone());
return cal;
}
public String formatCalendar(Calendar calendar) {
setTimeZone(calendar.getTimeZone());
String nocolon = format(calendar.getTime());
//add the colon
StringBuffer sb = new StringBuffer(nocolon.substring(0, nocolon.length() - 2)).append(":").append(nocolon.substring(nocolon.length() - 2));
return sb.toString();
}
}
}
I have following json response. I am not able to iterate through each Map. Please help me
{"status":"OK","result":{"1":{"Id":"3","Conferencce":"test3","Description":"test3","Admin":"919818559890","Moderator":null,"Keywords":"test3","StartDate":"2011-11-19 12:22:33","EndDate":"2011-11-19 14:22:33","Type":"both","MaxAtendee":"0","MinAtendee":"0","RegAtendee":"0","DescVoiceVideo":null,"Rating":null,"Status":"active","ApproveBy":null,"ApprovedOn":"2011-11-15 14:22:33","ApprovedReason":null,"AdminPin":null,"UserPin":null,"PricePerMin":null,"PricePerConf":null,"ReminderStart":null,"AdminJoin":null,"CreatedOn":"2011-11-17 13:31:27","CreatedBy":"1"},"2":{"Id":"2","Conferencce":"test2","Description":"test","Admin":"919818559899","Moderator":null,"Keywords":"test2","StartDate":"2011-11-18 12:22:33","EndDate":"2011-11-18 14:22:33","Type":"both","MaxAtendee":"0","MinAtendee":"0","RegAtendee":"0","DescVoiceVideo":null,"Rating":null,"Status":"active","ApproveBy":null,"ApprovedOn":"2011-11-15 12:22:33","ApprovedReason":null,"AdminPin":null,"UserPin":null,"PricePerMin":null,"PricePerConf":null,"ReminderStart":null,"AdminJoin":null,"CreatedOn":"2011-11-17 13:31:20","CreatedBy":"1"},"3":{"Id":"1","Conferencce":"test","Description":"tes","Admin":"919818559898","Moderator":null,"Keywords":"test","StartDate":"2011-11-17 12:22:33","EndDate":"2011-11-17 14:22:33","Type":"both","MaxAtendee":"0","MinAtendee":"0","RegAtendee":"0","DescVoiceVideo":null,"Rating":null,"Status":"active","ApproveBy":"1","ApprovedOn":"2011-11-15 12:22:33","ApprovedReason":null,"AdminPin":null,"UserPin":null,"PricePerMin":null,"PricePerConf":null,"ReminderStart":null,"AdminJoin":null,"CreatedOn":"2011-11-17 13:31:15","CreatedBy":"1"}}}
I am not able to iterate through each Map
Instead of treating the three components of the result response as maps, if the names of the keys are consistent and unchanging, I'd define a Java object to match the overall data structure along the following lines. Note this example uses Jackson to handle the JSON-to-Java conversion.
import java.io.File;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
import org.codehaus.jackson.annotate.JsonMethod;
import org.codehaus.jackson.map.ObjectMapper;
public class JacksonFoo
{
public static void main(String[] args) throws Exception
{
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(JsonMethod.ALL, Visibility.ANY);
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
Response response = mapper.readValue(new File("input.json"), Response.class);
for (Map.Entry<Integer, Result> entry : response.result.entrySet())
{
System.out.printf("Entry %1$d: %2$s\n", entry.getKey(), entry.getValue());
}
}
}
class Response
{
ResponseStatus status;
Map<Integer, Result> result;
}
enum ResponseStatus
{
OK, NOT_OK
}
class Result
{
int Id;
String Conferencce;
String Description;
BigInteger Admin;
String Moderator;
String Keywords;
Date StartDate;
Date EndDate;
String Type;
int MaxAtendee;
int MinAtendee;
int RegAtendee;
String DescVoiceVideo;
String Rating;
Status Status;
String ApproveBy;
Date ApprovedOn;
String ApprovedReason;
String AdminPin;
String UserPin;
String PricePerMin;
String PricePerConf;
String ReminderStart;
String AdminJoin;
Date CreatedOn;
int CreatedBy;
#Override
public String toString()
{
return String.format("Id: %1$d, Conferencce: %2$s, Description: %3$s, Admin: %4$d, StartDate: %5$tY-%5$tm-%5$td %5$tH:%5$tM:%5$tS", Id, Conferencce, Description, Admin, StartDate);
}
}
enum Status
{
active, inactive
}