Custom Scalar Type in graphql-spqr - java

I graphql-spqr, java.util.Date is defined as Scalar. Is it possible to overwrite the serialization/deserialization of java.util.Date to get a different String representation of the date?
The ScalarStrategy mentioned in this answer was removed with the latest release.
public class Order {
private String id;
private Date orderDate; //GraphQLScalarType "Date"
public Order() {
}
public Order(String id, String bookId, Date orderDate) {
this.id = id;
this.orderDate = orderDate;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Date getOrderDate() {
return orderDate;
}
public void setOrderDate(Date orderDate) {
this.orderDate = orderDate;
}
}
GraphQL Response:
{
"data": {
"createOrder": {
"id": "74e4816c-f850-4d63-9855-e4601fa125f4",
"orderDate": "2019-05-26T08:25:01.349Z", // --> 2019-05-26
}
}
}

ScalarStrategy isn't the proper way to achieve what you want. When you want to change how a Java type gets mapped to GraphQL, you normally provide a new (or customize an existing) TypeMapper.
Take a look at the existing Date scalar implementation and implement your own in a similar way. Then implement a custom TypeMapper that simply always returns a static instance of that scalar from both toGraphQLType and toGraphQLInputType methods.
public class CustomTypeMapper implements TypeMapper {
private static final GraphQLScalarType GraphQLCustomDate = ...;
#Override
public GraphQLOutputType toGraphQLType(...) {
return GraphQLCustomDate;
}
#Override
public GraphQLInputType toGraphQLInputType(...) {
return GraphQLCustomDate;
}
#Override
public boolean supports(AnnotatedType type) {
return type.getType() == Date.class; // This mapper only deals with Date
}
}
To register it, call generator.withTypeMappers(new CustomTypeMapper().
That said, since you're only trying to cut off the time part, you'd ideally use LocalDate here. You can make SPQR do that transparently by registering a TypeAdapter (which is nothing but a mapper + converter) but a simple mapper as explained above is a more efficient solution in your case. If you still decide to go the adapter way, you can inherit AbstractTypeAdapter<Date, LocalDate> and implement the conversion logic (should be trivial). Register via generator.withTypeAdapters or by registering it as a mapper and converters separately.

Related

generics with interfaces and validators

I have:
Generic interface with method isValid (T obj).
Driver class with parameters such as age, experience, license etc. VaLidator for
Driver Class which checks if Driver is Valid.
So I need a validator for the Driver class.
public class Driver <T>{
private String name;
private String surname;
private String secondname;
private int dateofbirth;
private T pass;
private T dateofissue;
public int getDateofbirth() {
return dateofbirth;
}
public T getPass() {
return pass;
}
public T getDateofissue() {
return dateofissue;
}
}
public interface Validator <T> {
boolean isValid (T obj);
}
class DriverValidator<T> implements Validator {
I do not know how I should do it. For any explanation will be very grateful
As mentioned in comments above it's not easy to help in this case, because the kind of validation is not known, also it's a little bit odd when seeing generic type is used 2 times by different getters. Also the dateOfBirth variable should be a long, a Date or a LocalDate.
But anyway, here is an example of an implementation of a validator to explain the technical concept (of course you have to add more checks, but the idea should be clear) :
public class DriverValidator<T> implements Validator<Driver<T>> {
#Override
public boolean isValid(Driver<T> driver) {
if (driver==null) {
return false;
}
if (driver.getPass() == null) {
/* e.g. when this field may not be null...*/
return false;
}
// ... do more checks - e.g. check old enough etc.
return true;
}
}

Hibernate One-To-Many Mapping, printing mapped lists

I have used One-to-Many Mapping in my project. I have stored a list of clicks for every user.
But when I retrieve the list by calling getClicks() methodm Hibernate returns list in different format.
Something like this.
"[com.zednx.tech.persistence.Click#29df9a77]"
So I tried Reading Every value from the list and assign to a new List.
List<Click> clicks=new ArrayList<Click>();
for(Click c: e.getClicks()){
Click temp = new Click();
temp.setAff_source(c.getAff_source());
temp.setCb_to_award(c.getCb_to_award());
temp.setCb_type(c.getCb_type());
clicks.add(temp);
}
But when i print the items of new List it stills prints the same way.
I need to build a JSON from the resulting String of this list.
So if the list is returned in format, it wont help me.
I couldn't find anything regarding this except How to pretty print Hibernate query results?
I tried Arrays.ToString(Object o). But it doesn't work.
GSON builder part-
Gson gson = new GsonBuilder()
.registerTypeAdapter(Click.class, new MyTypeAdapter<Click>())
.create();
List<Click> clicks=new ArrayList<Click>();
for(Click c: e.getClicks()){
Click temp = new Click();
temp.setAff_source(c.getAff_source());
temp.setCb_to_award(c.getCb_to_award());
temp.setCb_type(c.getCb_type());
temp.setCom_to_recieve(c.getCom_to_recieve());
temp.setStore_name(c.getStore_name());
temp.setT_date(c.getT_date());
temp.setT_status(c.getT_status());
temp.setT_ticket(c.getT_ticket());
temp.setUid(c.getUid());
System.out.println(c.toString());
clicks.add(temp);
}
String json = gson.toJson(clicks, Click.class);
Click.java
#Entity
#Table(name="click")
public class Click {
#Id
#Column(name="t_ticket")
private String t_ticket;
#Column(name="uid",nullable=false)
private long uid;
public long getUid() {
return uid;
}
public void setUid(long uid) {
this.uid = uid;
}
#ManyToOne
#JoinColumn(name="uid",
insertable=false, updatable=false,
nullable=false)
private Earning earning;
#Column(name="store_name")
private String store_name;
#Column(name="t_status")
private String t_status;
#Column(name="aff_source")
private String aff_source;
#Column(name="com_to_recieve")
private float com_to_recieve;
#Column(name="t_date")
private Date t_date;
#Column(name="cb_to_award")
private float cb_to_award;
#Column(name="cb_type")
private String cb_type;
public String getT_ticket() {
return t_ticket;
}
public void setT_ticket(String t_ticket) {
this.t_ticket = t_ticket;
}
public Earning getEarning() {
return earning;
}
public void setEarning(Earning earning) {
this.earning = earning;
}
public String getStore_name() {
return store_name;
}
public void setStore_name(String store_name) {
this.store_name = store_name;
}
public String getT_status() {
return t_status;
}
public void setT_status(String t_status) {
this.t_status = t_status;
}
public String getAff_source() {
return aff_source;
}
public void setAff_source(String aff_source) {
this.aff_source = aff_source;
}
public float getCom_to_recieve() {
return com_to_recieve;
}
public void setCom_to_recieve(float com_to_recieve) {
this.com_to_recieve = com_to_recieve;
}
public Date getT_date() {
return t_date;
}
public void setT_date(Date t_date) {
this.t_date = t_date;
}
public float getCb_to_award() {
return cb_to_award;
}
public void setCb_to_award(float cb_to_award) {
this.cb_to_award = cb_to_award;
}
public String getCb_type() {
return cb_type;
}
public void setCb_type(String cb_type) {
this.cb_type = cb_type;
}
Any Help is appreciated.
You need to implement a toString method, as your current Click class likely doesn't have one, so it just prints as the name of the class and instance identifier.
Okay, I could solve my problem finally.
I made another POJO without any annotations and Mapped the List items to that POJO class.
I think the problem was with Annotation of mapping on another class which I had in original POJO.
Also getString() method only helps in changing format of identifier. So basically it has nothing to do with JSON building unless you format getString() in form of JSON.
Hope it helps. If anyone wants new temp POJO I made I can post it if requested.
Thanks.

Finding non-referenced class attributes in Eclipse

I wonder if there are another ways to find attributes in specific class are non-referenced by other classes (I mean, non used attributes).
My way is like that, for example I have a class like:
public class EABHeaderInformation implements Serializable{
/**
*
*/
private static final long serialVersionUID = -4986763088497593972L;
//BargainFinder - AlternateBooking
private int multiTicketSequencdNmbr;
private String resBookDesigCode;
private LocalDateTime departureDate;
private LocalDateTime lastTicketingDate;
private List<String> text;
private String validatingCarrierCode;
public String getValidatingCarrierCode() {
return validatingCarrierCode;
}
public void setValidatingCarrierCode(String validatingCarrierCode) {
this.validatingCarrierCode = validatingCarrierCode;
}
public int getMultiTicketSequencdNmbr() {
return multiTicketSequencdNmbr;
}
public void setMultiTicketSequencdNmbr(int multiTicketSequencdNmbr) {
this.multiTicketSequencdNmbr = multiTicketSequencdNmbr;
}
public String getResBookDesigCode() {
return resBookDesigCode;
}
public void setResBookDesigCode(String resBookDesigCode) {
this.resBookDesigCode = resBookDesigCode;
}
public LocalDateTime getDepartureDate() {
return departureDate;
}
public void setDepartureDate(LocalDateTime departureDate) {
this.departureDate = departureDate;
}
public LocalDateTime getLastTicketingDate() {
return lastTicketingDate;
}
public void setLastTicketingDate(LocalDateTime lastTicketingDate) {
this.lastTicketingDate = lastTicketingDate;
}
public List<String> getText() {
return text;
}
public void setText(List<String> text) {
this.text = text;
}}
It's a simple POJO with getter and setters. I check every getter and setter with 'Open Call Hierarchy' in Eclipse, to find out if the attribute is used by others or not. But it takes a lot of time when I work on bigger classes than this.
So, is there a faster way to do this? Thanks for replies.
Eclipse can already create a warning or error for unused private members, but for public ones the Eclipse stance has always been that it's not a valuable feature. I tend to disagree, because many users have a limited scope that would be useful (specifically, all, or a subset of, the projects in the workspace). See this feature request, this one, and this one.
There are some third party options, such as UCDetector and this simple plug-in example.
See also this SO question and the answers.

Missing value for XmlElement

I should read every value of Turn element in the input XML:
<Section type="report" startTime="0" endTime="182.952">
<Turn speaker="spk1" startTime="7.186" endTime="8.114">
<Sync time="7.186"/>un souci avec une inscription
</Turn>
<Turn speaker="spk2" startTime="8.114" endTime="8.533">
<Sync time="8.114"/>ouais
</Turn>
<Turn speaker="spk1 spk2" startTime="8.533" endTime="9.731">
<Sync time="8.533"/>
<Who nb="1"/>first value!
<Who nb="2"/>second value!
</Turn>
</Section>
So I used JAXB and made the following classes:
Section:
#XmlRootElement(name="Section")
public class Section {
private List<Turn> turn;
#XmlElement(name="Turn")
public List<Turn> getTurn() {
if(turn == null){
turn = new ArrayList<Turn>();
}
return turn;
}
public void setTurn(List<Turn> turn) {
this.turn = turn;
}
}
Turn:
#XmlRootElement(name="Turn")
public class Turn {
private String speaker;
private float startTime;
private float endTime;
private Sync sync;
private String content;
private List<Who> whoList;
#XmlAttribute
public String getSpeaker() {
return speaker;
}
public void setSpeaker(String speaker) {
this.speaker = speaker;
}
public float getStartTime() {
return startTime;
}
#XmlAttribute
public void setStartTime(float startTime) {
this.startTime = startTime;
}
#XmlAttribute
public float getEndTime() {
return endTime;
}
public void setEndTime(float endTime) {
this.endTime = endTime;
}
#XmlValue
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
But when I want to read for example the value of Turn where speaker equals "spk1 spk2", the method getContent of Turn return only "second value!".. How i can get all content with "first value!" ?
I know is not allowed to set XmlElement with XmlValue for one Element, but I have no choice, the xml files are like that, and I should work with many files like that..
Thanks in advance :)
So you deal with mixed content. Have a look to the other question how-to-deal-with-jaxb-complextype-with-mixedcontent-data and jaxb-xmlmixed-usage-for-reading-xmlvalue-and-xmlelement. It would be manageable with the annotation #XmlMixed for your Turn class. Then, I'm not quite sure if you need the getter and setter methods for the content.
I think you problem comes from your declaration of #XmlElement(name="Turn"). If you have a look to the following tutorial from Vogella, you'll see he is using a wrapper for its list thanks to the annotation XmlElementWrapper and sets the annotations at the declaration of the list, not before the method, as following:
// XmLElementWrapper generates a wrapper element around XML representation
#XmlElementWrapper(name = "bookList")
// XmlElement sets the name of the entities
#XmlElement(name = "book")
private ArrayList bookList;
In your case, I think JAXB manage an object when you expect it to deal with a list of objects.

Can update field only once in GAE Datastore using Objectify

I am serializing Diagram class to GAE Datastore using Objectify. I can update (serialize) all the fields as many times as I want, except Integer arrowTypeId, that is only updated once, and after that keeps always the same value. If I leave the app and run it again, I can update again that value, but only once.
To update arroyTypeId I am calling sendDatabaseUpdateDiagramArrows(). This is what happens:
I call sendDatabaseUpdateDiagramArrows() with value 1
I set that value to the DiagramProxy.setArrowTypeId().
As a test, I change the diagram title to DiagramProxy.getArrowTypeId()
I call save()
On the DAO save(), the wrong value of ArrowTypeId is received (keeps the old one), but surprisingly, the Title has the right ArrowTypeId stored from step 3)
Changes are serialized with this problem. No exceptions are displayed.
Note that I am able to update ArrowTypeId value the first time, from default value 1 to 2. Buth the next time keeps always value 2.
Edit: If I change arrowTypeId to a String, I have the same issue.
DatabaseUtils.java
public static DiagramProxy sendDatabaseUpdateDiagramArrows(DialectiveRequestFactory requestFactory, Integer value, DiagramProxy cellDiagramProxy)
{
DiagramRequest diagramRequest = requestFactory.diagramRequest();
DiagramProxy newDiagramProxy = diagramRequest.edit(cellDiagramProxy);
Date date = new Date();
newDiagramProxy.setArrowTypeId(value);
newDiagramProxy.setTitle(Integer.toString(newDiagramProxy.getArrowTypeId()));
diagramRequest.save(newDiagramProxy).fire();
return cellDiagramProxy;
}
Diagram.java
#Entity
public class Diagram extends DatastoreObject{
#Indexed private String diagramId;
private String title;
private Integer arrowTypeId;
public String get_id() {
return diagramId;
}
public void set_id(String diagramId) {
this.diagramId = diagramId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Integer getArrowTypeId() {
return arrowTypeId;
}
public void setArrowTypeId(Integer arrowTypeId) {
this.arrowTypeId = arrowTypeId;
}
}
DiagramProxy.java
#ProxyFor(value = Diagram.class, locator = ObjectifyLocator.class)
public interface DiagramProxy extends EntityProxy{
void set_id(String id);
void setTitle(String title);
void setArrowTypeId(Integer arrowTypeId);
Integer getArrowTypeId();
String get_id();
String getTitle();
}
DiagramDao.java
public class DiagramDao extends ObjectifyDao<Diagram>{
public void save(Diagram diagram)
{
this.put(diagram);
} }
Let me guess :) as I don't have experience with GAE datastore.
I don't get the point, why you make
#Indexed private String diagramId;
but getter and setter with non-standard names:
public String get_id() {
return diagramId;
}
public void set_id(String diagramId) {
this.diagramId = diagramId;
}
I'd rather go for:
#Indexed private String diagramId;
public String getDiagramId() {
return diagramId;
}
public void setDiagramId(String diagramId) {
this.diagramId = diagramId;
}
One more thing is that DiagramRequest code has not been published, maybe that could help in seeing the problem.

Categories

Resources