How to use #GraphQLInterface in SPQR - graphql-spqr

I want to return list of interfaces with different implementations by calling query/mutation in grpahql spqr.
For this purpose I suppose I need to use #GraphQLInterface.
Maybe I doing something wrong, but it not works.
I have spring-boot app 2.3.3.RELEASE with graphql-spqr-spring-boot-starter 0.0.4
There is my model:
public class ResponseDto {
...
List<IValidation> validations;
}
#GraphQLInterface(name = "ValidationError", implementationAutoDiscovery = true)
public interface ValidationError {
#GraphQLQuery(name = "message")
String getMessage();
}
#GraphQLType(name = "SimpleError")
#AllArgsConstructor
#Getter
public enum SimpleError implements ValidationError {
ERROR("some msg");
private String message;
}
But when I get graphql schema there is no any info about SimpleError and field message in ValidationError.
I also tried without GraphQLType and GraphQLQuery, it not works.
And I tried with no enum implementation also, same result.
Could anyone explain what I'm doing wrong?
Thank you.

Related

Xamarin Android binding does not implement interface issue

I've a java binding for android which somewhat works bar the new feature I'm trying to integrate with. Only now I have realised that the intended callback is not happening. Here are the classes (decompiled to java) in question:
At the top level we have
public interface MyPackage {
MyPackage.Companion Companion = MyPackage.Companion.$$INSTANCE;
public static final class Companion {
#Nullable
private static MyEventHandler myEventHandler;
// $FF: synthetic field
static final MyPackage.Companion $$INSTANCE;
#Nullable
public final MyEventHandler getMyEventHandler() {
return myEventHandler;
}
public final void setMyEventHandler(#Nullable MyEventHandler var1) {
myEventHandler = var1;
}
private Companion() {
}
static {
MyPackage.Companion var0 = new MyPackage.Companion();
$$INSTANCE = var0;
}
}
}
MyEventHandler class:
public abstract class MyEventHandler {
public abstract void handleEvent(#NotNull String var1, #NotNull Properties var2);
}
Properties class:
import java.util.Map;
public class Properties extends r {
public Properties() {
}
Properties(Map<String, Object> var1) {
super(var1);
}
public Properties a(String var1, Object var2) {
super.b(var1, var2);
return this;
}
}
and the problematic r class:
public class r implements Map<String, Object> {
private final Map<String, Object> a;
various implementations...
}
So I noticed the issue when I couldnt override the HandleEvent method at the integration level and started looking at the Binding logs and found:
Warning=>
BINDINGSGENERATOR: Warning BG8801: Invalid parameter type MyPackage...Properties in method HandleEvent in managed type MyPackage.MyEventHandler. (BG8801)
And in build logs:
message BG0000: warning BG8102: Class MyPackage....Properties has unknown base type MyPackage....r.
warning BG8801: Invalid parameter type MyPackage...Properties in method HandleEvent in managed type MyPackage.MyEventHandler.
As it was obvious r is an obfuscated class I need to make chagnes to my Metadata so I went ahead and popped in:
<attr path="/api/package[#name='MyPackage']/class[#name='r']" name="obfuscated">false</attr>
Which resulted in the R being generated but now I get the 5 following compile error:
Error CS0535: 'R' does not implement interface member 'IMap.EntrySet()' (CS0535)
Error CS0738: 'R' does not implement interface member 'IMap.KeySet()'. 'R.KeySet()' cannot implement 'IMap.KeySet()' because it does not have the matching return type of 'ICollection'. (CS0738)
Error CS0535: 'R' does not implement interface member 'IMap.Put(Object?, Object?)' (CS0535)
Error CS0535: 'R' does not implement interface member 'IMap.PutAll(IDictionary?)' (CS0535)
Error CS0738: 'R' does not implement interface member 'IMap.Values()'. 'R.Values()' cannot implement 'IMap.Values()' because it does not have the matching return type of 'ICollection'. (CS0738)
I tried to make a managed return using
<attr path="/api/package[#name='MyPackage']/class[#name='r']/method[#name='entrySet' and count(parameter)=0]" name="managedReturn">Java.Util.IMap</attr>
With same number of compile error as above. Then I tried removing the node using:
<remove-node path="/api/package[#name='MyPackage']/class[#name='r']/method[#name='entrySet']"/>
Still no luck. :(
What am I missing here? Any pointers/suggestions will be appreciated!
It seems like you are trying to expose a Map to C# and as you stated, Java Generics are not handled very well.
In a very popular social network you received an answer from #mattleibow. I do not take credit for his answer but I went to check nonetheless and it seems fine.
If you look at the description of the Java.Lang.HashMap type
https://learn.microsoft.com/en-us/dotnet/api/java.util.hashmap?view=xamarin-android-sdk-9 it's a good candidate for you to expose.
You can also try with the corresponding interface for better safety https://learn.microsoft.com/en-us/dotnet/api/java.util.imap?view=xamarin-android-sdk-9
If it works you will still have to cast the types yourself.
Please answer to the comment to say that problem is solved for the sake of future generations arriving on this post :D
Credit is not mine so don't give it to me :-)
John,
I got arround fixing it by providing implementation of the the said methods in a partial class. Basically added a new file called R.cs under Additions folder as follows:
namespace YourNameSpace
{
public partial class R
{
public void PutAll(System.Collections.IDictionary p0)
{
PutAll(p0);
}
public Java.Lang.Object Put(Java.Lang.Object key, Java.Lang.Object value)
{
return Put(key, value);
}
public System.Collections.ICollection EntrySet()
{
return EntrySet();
}
public System.Collections.ICollection KeySet()
{
return KeySet();
}
public System.Collections.ICollection Values()
{
return Values();
}
}
}
I couldn't get it to work by adding XML transformation, but I think there was some tooling issue.

Mapper decorator not getting compiled

Mapper decorator for my mapper is not getting compiled.Mapper is getting compiled, but not the decorator. Because, during the build I'm getting the type conversion error, even though I'm doing it in the mapper decorator. Is there anything more to add?
mapper code:
#Mapper
#DecoratedWith(OneMapperDecorator.class)
public interface OneMapper {
public TwoObject convertToTwoObject(OneObject one);
}
decorator code:
public abstract class OneMapperDecorator implements OneMapper {
private final OneMapper delegate;
public OneMapperDecorator (OneMapper delegate) {
this.delegate = delegate;
}
#Override
public TwoObject convertToTwoObject(OneObject one)
{
TwoObject two=delegate.convertToTwoObject(one);
two.setTotalFare(new BigDecimal(one.getPrice()));//string to bigdecimal conversion
return two;
}
}
The decorator is meant to augment the mapping not to replace it. MapStruct has no way of knowing that you are mapping your totalFare in the decorator. You have 2 options:
Define a custom mapping method
In your OneMapper you can add a default method that would perform the mapping (as the error says.
#Mapper
#DecoratedWith(OneMapperDecorator.class)
public interface OneMapper {
#Mapping(target = "totalFare", source = "price");
TwoObject convertToTwoObject(OneObject one);
default BigDecimal map(String value) {
return value == null ? null : new BigDecimal(value);
}
}
Ignore the mapping
In case you want to do the mapping in your decorator then you need to tell MapStruct to not map it.
#Mapper
#DecoratedWith(OneMapperDecorator.class)
public interface OneMapper {
#Mapping(target = "totalFare", ignore = true);
TwoObject convertToTwoObject(OneObject one);
}
One advise from me if you are using your delegate only to map extra fields I would either add custom methods or use #AfterMapping and #BeforeMapping to handle that.

How to pass a generic collection Class object as an argument

I've RESTful service Spring MVC based.
The service has a RESTful resource method that returns the following response:
public class OperationalDataResponse<T> {
private String status;
private String statusMessage;
private T result;
//getters and setters
}
This response object encapsulates the result object of type T.
On the client side I use RestTemplate with GsonHttpMessageConverter added.
I get the response from service as a ResponseEntity
I handle the generic response with runtime Type as below:
public class OperationalDataRestClient<REQ,RESULT_TYPE> {
public OperationalDataResponse<RESULT_TYPE> getOperationalData(String resourcePath, Map<String, Object> urlVariables, Class<RESULT_TYPE> resultType) {
//code to invoke service and get data goes here
String responseString = responseEntity.getBody();
response = GsonHelper.getInstance().fromJson(responseString, getType(OperationalDataResponse.class, resultType));
}
Type getType(final Class<?> rawClass, final Class<?> parameter) {
return new ParameterizedType() {
#Override
public Type[] getActualTypeArguments() {
return new Type[] { parameter };
}
#Override
public Type getRawType() {
return rawClass;
}
#Override
public Type getOwnerType() {
return null;
}
};
}
}
This works like a charm as long as my resultType is a non-collection class.
So, this works great from caller code:
getOperationalData(someResourcePath, someUrlVariables, MyNonGenericClass.class)
However if my resultType is a collection (say, List<String> or List<MyNonGenericClass>)
then I don't know how to pass the resultType Class from the caller code.
For example, from caller code,
getOperationalData(someResourcePath, someUrlVariables, List.class)
or
getOperationalData(someResourcePath, someUrlVariables, List<MyNonGenericClass>.class)
throws compilation error.
I tried passing on ArrayList.class as well but that too doesn't work.
Any suggestion how can I pass a generic collection as a resultType from caller code (in other words, as an example, how can I pass the class object of a List<String> or List<MyNonGenericClass> from caller code ?)
If you know that ResultType is coming as a List, Then it will obvious fail like you said compilation issue.Why? because you are trying to send a List when you method only accepts a single value.In order to over come that issue you will have to change the method arguments to the following
public OperationalDataResponse<RESULT_TYPE> getOperationalData(String resourcePath, Map<String, Object> urlVariables, List<Class<RESULT_TYPE>> resultType){
....
}
and you will have to make some slight modification to getType() Method,loop it and then pass each class value to getType method like so
for(MyNonGenericClass myClass:mylist){
getType(OperationalDataResponse.class, myClass.getClass());
}

Atmosphere: The method getDefault() from the type BroadcasterFactory is deprecated

I'm using Atmosphere 2.2.0-RC3. And I have this warning: "The method getDefault() from the type BroadcasterFactory is deprecated" in the line BroadcasterFactory.getDefault().lookup(topic, true)
Here is the code:
#Path("/chat/{topic}")
#AtmosphereService (broadcaster = JerseyBroadcaster.class)
public class ChatResourceTopic {
private #PathParam("topic")
String topic;
#Suspend( contentType = MediaType.APPLICATION_JSON, listeners = { OnDisconnect.class })
#GET
public Broadcastable suspend() {
return new Broadcastable(BroadcasterFactory.getDefault().lookup(topic, true ));
}
...
}
I have checked the wiki and is widely used: https://github.com/Atmosphere/atmosphere/wiki/Understanding-Broadcaster
How could I change the code to avoid the warning?
Note: I also use this in:
BroadcasterFactory.getDefault().lookup(topic).broadcast(response);
I don't use Jersey with Atmosphere (I use #ManagedService) but you should be able to inject either an AtmosphereResource or BroadcasterFactory with the #Context annotation when you use Jersey.
public Broadcastable suspend(#Context BroadcasterFactory factory) {
OR
public Broadcastable suspend(#Context AtmosphereResource resource) {
BroadcasterFactory factory = resource.getAtmosphereConfig().getBroadcasterFactory();
I have not tested this but it's in older documentation

signature get error on Alljoyn framework?

i'm working Android App use Alljoyn framework and i have some prolem
i have a custom object
public class Package implements BusObject {
public static enum DataSendType {
TEXT,IMAGE
}
public static enum PackageStatus {
NONE, SENDING, DONE
}
#Signature("s")
private String m_id;
#Signature("a")
private ArrayList<DataPackage> m_listPackage;
#Signature("r")
private PackageStatus m_status;
#Signature("r")
private DataSendType m_type;
#Signature("s")
private String m_packageName;
}
and interface
#BusInterface (name="xxxx.simpleinterface")
public interface SimpleInterface {
#BusSignal (name="Chat", signature="o")
public void Chat(Package message) throws BusException;
}
but i get this error cannot marshal class Package into 'o' when use Chat(Package)..
pls help me, because i can't get this error out for 2 weeks.
sorry because my English is too bad :)
looking at your code it looks like what you are trying to send is a struct the signature for a struct should be "r" or the actual signature surrounded by parenthesizes ( and ). i.e. for Package the signature would be "(sayiis)"
With AllJoyn you can send an array but not an ArrayList and you must specify the type of data that is in the array.
Since your DataSendType specified TEXT or IMAGE I made the assumption that you want to send an array of bytes.
Most of the items I did not add a signature to because AllJoyn can figure out the signature using reflection. AllJoyn however does not know that enums will be transmitted as integers so I did have to specify the signature for the enums.
Package did not have to implement BusObject. In your code when you implement your SimpleInterface that should extend the SimpleInterface and `BusObject'
Anything sent using AllJoyn should be public so the interface can read the member variables.
public class Package {
public static enum DataSendType{
TEXT,
IMAGE
}
public static enum PackageStatus {
NONE,
SENDING,
DONE
}
#Position(0)
public String m_id;
#Position(1)
public byte[] m_listPackage;
#Position(2)
#Signature("i")
public PackageStatus m_status;
#Position(3)
#Signature("i")
public DataSendType m_type;
#Position(4)
public String m_packageName;
}
for the interface the signature should be "r" for struct the signature "o" means object path. This is an AllJoyn object path which means it just a string with path data.
#BusInterface (name="xxxx.simpleinterface")
public interface SimpleInterface {
#BusSignal (name="Chat", signature="r")
public void Chat(Package message) throws BusException;
}
If you really need to use an ArrayList convert the ArrayList to an actual array before sending the Chat signal.

Resources