GraphQL : Query failed to validate - graphql

I'm testing graph-spqr librabry in a simple java program.
This is what I've done so far:
public class GraphQLResolver {
private String status;
private Integer price;
#GraphQLMutation(name="updateStatusOrder")
public void updateStatusOrder(#GraphQLArgument(name="id") String orderId,#GraphQLArgument(name="status") String status) {
//to do
}
#GraphQLQuery(name="getStatus")
public String getStatus(#GraphQLArgument(name="id") String orderId) {
this.status="Example of status";
return this.status;
}
}
Then, I calling building GraphQL methods in main method
public class Main {
public static void main(String[] args) {
GraphQLSchema schema = new GraphQLSchemaGenerator()
.withOperationsFromSingleton(new GraphQLResolver())
.generate(); //done ;)
GraphQL graphQL = new GraphQL.Builder(schema).build();
ExecutionResult result = null;
result = graphQL.execute("{getstatus(id:123){status}}");
}
}
I have error : Query failed to validate : '{status(id:123){status}}'
What is wrong?

I guess the correct query should be :
{
getstatus(id:"123")
}
with the following reasons :
You define the id argument as String , so need to use double quote around the argument value.
The getStatus query is defined to return a String which is a scalar but not an object type in term of GraphQL. So you don't need to further define what of its fields to be returned as the scalar does not have any fields for you to pick.

Related

How do I add a Type to a graphql-java-annotations project?

The documentation for graphql-java-annotations doesn't do such a great job of telling me how to add a Custom Scalar to my schema: https://github.com/Enigmatis/graphql-java-annotations/tree/v8.0.1#annotations-schema-creator
What I need is to create some 'scalar Date' in the Schema. It is unclear how to do this with the AnnotationsSchemaCreator builder thing.
GraphQLSchema schema = AnnotationsSchemaCreator.newAnnotationsSchema()
.query(Query.class) // to create you query object
.mutation(Mutation.class) // to create your mutation object
.subscription(Subscription.class) // to create your subscription object
.directive(UpperDirective.class) // to create a directive
.additionalType(AdditionalType.class) // to create some additional type and add it to the schema
.typeFunction(CustomType.class) // to add a typefunction
.setAlwaysPrettify(true) // to set the global prettifier of field names (removes get/set/is prefixes from names)
.setRelay(customRelay) // to add a custom relay object
.build();
The docs give me just that. Is a typeFunction what I need here? Do I have to first get the graphql-java "Custom Scalar" stuff set up and put that into the typeFunction?
What's happening right now is that my graphql-java-annotations Types which need the Date type...
public abstract class BasePart {
#GraphQLField
#GraphQLNonNull
#JsonIgnore
public String id;
...
#GraphQLField
public Date createdOn;
...
}
Get into the Schema without the Date scalar defined so the GraphiQL UI is rejecting it with errors like...
Error: Date fields must be an object with field names as keys or a function which returns such an object.
at invariant (http://localhost.blueorigin.com:8080/webjars/graphiql/0.10.1/graphiql.min.js:13:12678)
at defineFieldMap (http://localhost.blueorigin.com:8080/webjars/graphiql/0.10.1/graphiql.min.js:14:16395)
at e.getFields (http://localhost.blueorigin.com:8080/webjars/graphiql/0.10.1/graphiql.min.js:14:22028)
at http://localhost.blueorigin.com:8080/webjars/graphiql/0.10.1/graphiql.min.js:15:22055
at typeMapReducer (http://localhost.blueorigin.com:8080/webjars/graphiql/0.10.1/graphiql.min.js:15:22227)
at http://localhost.blueorigin.com:8080/webjars/graphiql/0.10.1/graphiql.min.js:15:22200
at Array.forEach (<anonymous>)
at http://localhost.blueorigin.com:8080/webjars/graphiql/0.10.1/graphiql.min.js:15:22082
at typeMapReducer (http://localhost.blueorigin.com:8080/webjars/graphiql/0.10.1/graphiql.min.js:15:22227)
at typeMapReducer (http://localhost.blueorigin.com:8080/webjars/graphiql/0.10.1/graphiql.min.js:15:21564)
I'm trying to figure out how to get that information into the, what, AnnotationsSchemaCreator.newAnnotationsSchema() builder?
How do you add a Custom Scalar to a graphql-java-annotations project?
The TypeFunction is the key. You pass the TypeFunction when you are building the Schema with the AnnotationsSchemaCreator. The following code effectively got scalar Date into the service's GraphQL Schema
graphQLSchema = AnnotationsSchemaCreator.newAnnotationsSchema()
.query(QuerySchema.class)
.setAlwaysPrettify(true)
.typeFunction(new MyDateTypeFunction()) // <-- This got scalar Date onto the schema
.build();
The TypeFunction itself realizes the support for the scalar Date.
public class MyDateTypeFunction implements TypeFunction {
#Override
public boolean canBuildType(Class<?> clazz, AnnotatedType annotatedType) {
return clazz == java.util.Date.class;
}
#Override
public GraphQLType buildType(
boolean b,
Class<?> clazz,
AnnotatedType annotatedType,
ProcessingElementsContainer processingElementsContainer) {
return MY_DATE;
}
public static final GraphQLScalarType MY_DATE = GraphQLScalarType
.newScalar()
.name("Date")
.description("Coerce java.util.Date to/from a String representation of the long value of getTime().")
.coercing(
new Coercing() {
#Override
public Object serialize(Object dataFetcherResult) throws CoercingSerializeException {
if (dataFetcherResult instanceof Date) {
final String result = String.format("%d", ((Date) dataFetcherResult).getTime());
return result;
}
final String message =
String.format("Expected type java.util.Date but found %s", typeName(dataFetcherResult));
throw new CoercingSerializeException(message);
}
#Override
public Object parseValue(Object input) throws CoercingParseValueException {
if (input instanceof String) {
try {
return stringToDate((String) input);
} catch (NumberFormatException nfe) {
final String message = String.format("NumberFormatException %s", nfe.getMessage());
throw new CoercingParseValueException(message);
}
}
final String message = String.format("Unable to parseValue %s to a java.util.Date", input);
throw new CoercingParseValueException(message);
}
#Override
public Object parseLiteral(Object input) throws CoercingParseLiteralException {
if (input instanceof StringValue) {
try {
final String inputStringValue = ((StringValue) input).getValue();
return stringToDate(inputStringValue);
} catch (NumberFormatException nfe) {
final String message = String.format("NumberFormatException %s", nfe.getMessage());
throw new CoercingParseLiteralException(message);
}
}
final String message = String.format("Unable to parseLiteral %s to a java.util.Date", input);
throw new CoercingParseLiteralException(message);
}
}
)
.build();
public static Date stringToDate(String input) throws NumberFormatException {
final long inputAsLong = Long.parseLong(input);
return new Date(inputAsLong);
}
public static String typeName(Object input) {
return input == null ? "null" : input.getClass().getName();
}
}
Note that I'm not recommending that you represent java.util.Date as the String value of the long getTime(), java.time.Instant's ISO-8601 is so much more readable, but my service needed this string value and this is how I got it into a graphql-java-annotation's project schema.

Trying to bind request parameters to nested object with spring controller using the dot notation and I keep getting a bad request error

I have searched and everything seems to say as long as you use spring 4+ I should be able to use dot notation to bind request parameters to a pojo.
This is what my request looks like:
And this is what my controller looks like:
And my dto:
I even tried adding #RequestParam("p.page") int page in the controller to make sure my endpoint was getting hit and it does. Am I missing something obvious or am I not allowed to use dot notation to populate a pojo with a spring controller?
And the parent class:
public class JhmPageableDto
{
private String query;
private int page;
private int size;
private String sort;
private boolean sortAsc;
public String getQuery()
{
return query;
}
public void setQuery(String query)
{
this.query = query;
}
public int getPage()
{
return page;
}
public void setPage(int page)
{
this.page = page;
}
public int getSize()
{
return size;
}
public void setSize(int size)
{
this.size = size;
}
public String getSort()
{
return sort;
}
public void setSort(String sort)
{
this.sort = sort;
}
public boolean isSortAsc()
{
return sortAsc;
}
public void setSortAsc(boolean sortAsc)
{
this.sortAsc = sortAsc;
}
}

Multiple Predicates to group collection to hashmap

I have a list of Objects as below -
List<Transaction>
where the Transaction Object will look like
Transaction {
String Status;
}
Status <A,B,C,D,E,F,G...>
If Status in (A,B,C)->Success
If Status in (D,E,F)->Failure
If Status in (G,H...)->Pending
Individual Predicates for identifying each status transaction are defined.
Expected output would be a hashmap with the Success/Failure/Rejected text as key and collective count of these statuses as value
HashMap<String, Integer> ->
{
"Success": 1,
"Failure":2,
"Pending":2
}
I am unable to proceed how to do this in a single execution. Right now, I get the counts separately. Can anyone please assist with the request?
You may first declare an enum like this to represent the 3 states that you are interested in.
public enum TxStatus {
Success, Failure, Pending;
}
Then write a method in Transaction to transform the String literal value into a real status value that you expect. Here's a one such implementation.
public class Transaction {
private final String status;
private Pattern SUCCESS_PATTERN = Pattern.compile("[ABC]");
private Pattern FAILURE_PATTERN = Pattern.compile("[DEF]");
private Pattern PENDING_PATTERN = Pattern.compile("[GHI]");
public Transaction(String status) {
super();
this.status = status;
}
public String getStatus() {
return status;
}
public TxStatus interpretStatus() {
if (SUCCESS_PATTERN.matcher(status).matches()) {
return TxStatus.Success;
}
if (FAILURE_PATTERN.matcher(status).matches()) {
return TxStatus.Failure;
}
if (PENDING_PATTERN.matcher(status).matches()) {
return TxStatus.Pending;
}
throw new IllegalArgumentException("Invalid status value.");
}
}
Finally your client code should look something like this,
Map<String, Long> txStatusToCountMap = txs.stream()
.collect(Collectors.groupingBy(tx -> tx.interpretStatus().toString(),
Collectors.counting()));

Oracle char type issue in Hibernate HQL query

I have Oracle table, which contains char type columns. In my Entity class i mapped oracle char type to java string type.
Here is the code for my Entity class.
#Entity
#Table(name="ORG")
public class Organization {
private String serviceName;
private String orgAcct;
//Some other properties goes here...
#Column(name="ORG_ACCT", nullable=false, length=16)
public String getOrgAcct() {
return this.orgAcct;
}
public void setOrgAcct(String orgAcct) {
this.orgAcct = orgAcct;
}
#Column(name="SERVICE_NAME",nullable=true, length=16)
public String getServiceName() {
return this.serviceName;
}
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
}
Here both serviceName and orgAcct are char type variables in Oracle
In my DAO class I wrote a HQL query to fetch Oranization entity object using serviceName and orgAcct properties.
#Repository
#Scope("singleton") //By default scope is singleton
public class OrganizationDAOImpl implementsOrganizationDAO {
public OrganizationDAOImpl(){
}
public Organization findOrganizationByOrgAcctAndServiceName(String orgAcct,String serviceName){
String hqlQuery = "SELECT org FROM Organization org WHERE org.serviceName = :serName AND org.orgAcct = :orgAct";
Query query = getCurrentSession().createQuery(hqlQuery)
.setString("serName", serviceName)
.setString("orgAct", orgAcct);
Organization org = findObject(query);
return org;
}
}
But when I call findOrganizationByOrgAcctAndServiceName() method , I am getting Organization object as null(i.e. HQL query is not retrieving Char type data ).
Please help me to fix this issue. Here I can't change Oracle type char to Varchar2. I need to work with oracle char type variables.
#EngineerDollery After going throw above post, I modified my Entity class with columnDefinition , #Column annotation attribute.
#Column(name="SERVICE_NAME",nullable=true,length=16,columnDefinition="CHAR")
public String getServiceName() {
return this.serviceName;
}
But still I am not able to retrieve the data for corresponding columns.
and I added column size as well in columnDefinition attribute.
#Column(name="SERVICE_NAME",nullable=true,length=16,columnDefinition="CHAR(16)
But still same issue I am facing.
Any thing Am I doing wrong. Please help me.
I resolved this problem using OraclePreparedStatement and Hibernate UserType interface.
Crated a new UserType class by extending org.hibernate.usertype.UserType interface and provided implementation for nullSafeSet(), nullSafeGet() methods .
nullSafeSet() method, we have first parameter as PreparedStatement, inside the method I casted PreparedStatement into OraclePreparedStatement object and pass String value using setFixedCHAR() method.
Here is the complete code of UserType impl class.
package nc3.jws.persistence.userType;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import org.apache.commons.lang.StringUtils;
import org.hibernate.type.StringType;
import org.hibernate.usertype.UserType;
/**
*
* based on www.hibernate.org/388.html
*/
public class OracleFixedLengthCharType implements UserType {
public OracleFixedLengthCharType() {
System.out.println("OracleFixedLengthCharType constructor");
}
public int[] sqlTypes() {
return new int[] { Types.CHAR };
}
public Class<String> returnedClass() {
return String.class;
}
public boolean equals(Object x, Object y) {
return (x == y) || (x != null && y != null && (x.equals(y)));
}
#SuppressWarnings("deprecation")
public Object nullSafeGet(ResultSet inResultSet, String[] names, Object o) throws SQLException {
//String val = (String) Hibernate.STRING.nullSafeGet(inResultSet, names[0]);
String val = StringType.INSTANCE.nullSafeGet(inResultSet, names[0]);
//System.out.println("From nullSafeGet method valu is "+val);
return val == null ? null : StringUtils.trim(val);
}
public void nullSafeSet(PreparedStatement inPreparedStatement, Object o,
int i)
throws SQLException {
String val = (String) o;
//Get the delegatingStmt object from DBCP connection pool PreparedStatement object.
org.apache.commons.dbcp.DelegatingStatement delgatingStmt = (org.apache.commons.dbcp.DelegatingStatement)inPreparedStatement;
//Get OraclePreparedStatement object using deletatingStatement object.
oracle.jdbc.driver.OraclePreparedStatement oraclePreparedStmpt = (oracle.jdbc.driver.OraclePreparedStatement)delgatingStmt.getInnermostDelegate();
//Call setFixedCHAR method, by passing string type value .
oraclePreparedStmpt.setFixedCHAR(i, val);
}
public Object deepCopy(Object o) {
if (o == null) {
return null;
}
return new String(((String) o));
}
public boolean isMutable() {
return false;
}
public Object assemble(Serializable cached, Object owner) {
return cached;
}
public Serializable disassemble(Object value) {
return (Serializable) value;
}
public Object replace(Object original, Object target, Object owner) {
return original;
}
public int hashCode(Object obj) {
return obj.hashCode();
}
}
Configured this class with #TypeDefs annotation in Entity class.
#TypeDefs({
#TypeDef(name = "fixedLengthChar", typeClass = nc3.jws.persistence.userType.OracleFixedLengthCharType.class)
})
Added this type to CHAR type columns
#Type(type="fixedLengthChar")
#Column(name="SERVICE_NAME",nullable=true,length=16)
public String getServiceName() {
return this.serviceName;
}
char types are padded with spaces in the table. This means that if you have
foo
in one of these columns, what you actually have is
foo<space><space><space>...
until the actual length of the string is 16.
Consequently, if you're looking for an organization having "foo" as its service name, you won't find any, because the actual value in the table if foo padded with 13 spaces.
You'll thus have to make sure all your query parameters are also padded with spaces.

Why it seems impossible to use BeanUtils.copyProperties from a JPA entity to a JAX-B Bean?

We are using JPA Entities to get the database rows and then when we transfer that to the external, we want to use disconnected object (DTO) which are simple beans annotated with JAX-B.
We use a mapper and its code looks like this:
public BillDTO map(BillEntity source, BillDTO target) {
BeanUtils.copyProperties(source, target);
return target;
}
But when the code is running we get an error like this:
java.lang.IllegalArgumentException: argument type mismatch
Note this is the Spring implementation of the BeanUtils:
import org.springframework.beans.BeanUtils
And the naming of the properties are identical (with their getter/setter).
Anybody knows why the error happens?
And how to use a fast way instead just copying properties one by one?
This example working well. Here String property is copied to enum property:
Entity:
public class A {
private String valueFrom;
public String getValue() {
return valueFrom;
}
public void setValue(String value) {
this.valueFrom = value;
}
}
DTO (En is enumeration):
public class B {
private En valueTo;
public void setValue(String def) {
this.valueTo = En.valueOf(def);
}
public void setEnumValue(En enumVal) {
this.valueTo = enumVal;
}
}
As for your GitHub example, problem in class B in getter should be:
public String getValue()
Example:
public String getValue() {
return value.toString();
}

Resources