Overriding standard ID scalar - graphql

I want to use UUID as an identifier but standard scalar ID is coerced as string.
So have to parse uuid from string everywhere I use ID type.
I wonder is it possible to override ID type with my own implementation?
This scalar type has some special meaning or I can just use my own scalar called UUID as identifier?

We can not override the available scalers, please refer this link for discussion.
You can define a UUIDScalar in your code, for the same you will have to override the following methods
#Override
public Object serialize(Object dataFetcherResult) {
//
}
#Override
public Object parseValue(Object input) {
//
}
#Override
public Object parseLiteral(Object input) {
//
}
Reference: Making custom scalars in graphql java
Luckily the code for making custom scalar for UUID is available online, you can use this PR

Related

Can't get Nest.PropertyName to be considered for nested

I have a type of entry in elastic that is made of some imbricated properties like
{
"_source":
{
"pipeline_version":1.7,
"agent":{
"hostname":"SFPWEW11616",
"id":"a1df2f4e-6dde-43fd-8af6-b3726124fdf7",
"type":"winlogbeat",
"ephemeral_id":"78be9770-dab9-4c56-a67e-b1a372a2f899",
"version":"7.5.1"
}
}, [...]
}
I'm trying to get my POCO to represent a flatten vie of this object. According to what I found in the documentation, I tried doing something in the like of
Friend Class ElasticEventLogEntry
<Nest.PropertyName("agent.hostname")>
Public Property AgentHostName As String
[...]
End Class
But no matter what I try, the value is always empty. I've seen some other posts using the NestedAttribute attribute but from what I could find, this is only useful if we want to also create nested objects in our POCO structure which isn't my case. What am I missing?
It's not possible to do what you're trying to do, at least not without writing your own JSON serialization for your ElasticEventLogEntry type and hooking up with JsonNetSerializer.
A better approach would be to model ElasticEventLogEntry differently
Public Class ElasticEventLogEntry
<DataMember(Name:="pipeline_version")>
Public Property PipelineVersion As String
Public Property Agent As Agent
End Class
Public Class Agent
Public Property Hostname As String
Public Property Id As String
Public Property Type As String
<DataMember(Name:="ephemeral_id")>
Public Property EphemeralId As String
Public Property Version As String
End Class
Then agent hostname will be deserialized to .Agent.Hostname

How to implement a translate function in ZK with EL

My webapp has a smart Java translator so I can't use a simple Label-based i18n in ZK. Instead of that, my smart translator method with two parameters - the key and the language - should be called, but the current language should be get from some webapp scope.
It would be very useful to have an EL function
<textbox value="${x:translate('some.i18n.key')}"/>
that call my smart translator method with the given String parameter and the current language code from the session.
What I could do is to define a 2-parameter translate method
<?xel-method prefix="x" name="translate"
class="mypackage.Translator"
signature="java.lang.Class translate(java.lang.String,java.lang.String)"?>
and use it as
<textbox value="${x:translate('qqq',sessionScope.get('LANGUAGE'))}"/>
but writing the second parameter every times is not a good solution. It can be written a bit shorter as
<textbox value="${x:translate('qqq',LANGUAGE)}"/>
or perhaps choose a shorter key instead of LANGUAGE, but I am interested in a more compact form.
Is it possible to define such a function that gets this second parameter implicitly? Or somehow to call a method of an object in the session/desktop/page scope from EL?
We use MVVM pattern with ZK and translation was one area where zk references make their way into your view models. To reduce it's impact we did:
Created a Translator interface:
public interface Translator {
String translate(String key);
// used where the string to be translation includes placeholders
// total_qty=Total qty: {1}
String translate(String key, String... params);
}
and a translator implementation:
public class ZKTranslator implements Translator {
#Override
public String translate(String s) {
String translation = Labels.getLabel(s);
if (translation == null)
return s;
return translation;
}
#Override
public String translate(String key, String... params) {
String translation = Labels.getLabel(key, params);
if (translation == null)
return key;
return translation;
}
}
This implementation may reference the session to retrieve a language or maybe (and preferable) the language is passed to ZKTranslator on initialisation.
It is then used as follows. In your view model:
public class SomeScreenVM {
private Translator translator;
#Init
public void init() {
// get language from session possibly
translator = new ZKTranslator(); // or new ZKTtanslator(language);
}
public String translate(String s) {
return translator.translate(s);
}
}
And in your zul file:
<window viewModel="#id('vm')" #init('com.example.SomeScreenVM')>
<label value="#load(vm.translate('hello'))"/>
</window>
Custom taglibs is the solution you need.
It exist in ZK :
https://www.zkoss.org/wiki/ZUML_Reference/ZUML/Processing_Instructions/taglib/Custom_Taglib
I can (miss)use the map support of EL in order to call a non-static, one-parameter method of an object.
First, I need a translator object implementing java.util.Map that can translate a String in its get() method:
public class Translator implements Map<String, String> {
private String language;
public Translator(String language) {
super();
this.language = language;
}
#Override
public String get(Object arg0) {
return translate(arg0.toString(), language);
}
...
}
Then I can put a translator into the desktop scope and use it in EL:
<zscript>
desktopScope.put("tr",new mypackage.Translator(sessionScope.get("language")));
</zscript>
<textbox value="${tr.some_key}"/>
<textbox value="${tr['some.hierarchical.key']}"/>
It is really not a clear solution, but makes the work with ZUL files rather simple.

Spring Data MongoDB: Dynamic field name converter

How do I set the MongoDB Document field name dynamically (without using #Field)?
#Document
public class Account {
private String username;
}
For example, field names should be capitalized. Result:
{"USERNAME": "hello"}
And I want this dynamic converter to work with any document, so a solution without using generics.
This a bit strange requirement. You can make use of Mongo Listener Life cycle events docs.
#Component
public class MongoListener extends AbstractMongoEventListener<Account> {
#Override
public void onBeforeSave(BeforeSaveEvent<Account> event) {
DBObject dbObject = event.getDBObject();
String username = (String) dbObject.get("username");// get the value
dbObject.put("USERNAME", username);
dbObject.removeField("username");
// You need to go through each and every field recursively in
// dbObject and then remove the field and then add the Field you
// want(with modification)
}
}
This is a bit cluncky, but I believe there is no clean way to do this.

Web API ModelBinders - how to bind one property of your object differently

I have the following action signature
[ValidateInput(false)]
public HttpResponseMessage PostParam(Param param)
With Param looking something like this:
public class Param {
public int Id { get; set;}
public string Name { get; set; }
public string Choices { get; set; }
}
Here's the hitch - what comes over the wire is something like this
{
Id: 2,
Name: "blah",
Choices: [
{
foo: "bar"
},
{
blah: "blo"
something: 123
}
]
}
I don't want "Choices" to deserialize - I want it stored as a string (yes, I understand the security implications). Understandably, I get an error because since the default binder does not know this.
Now with Asp Mvc creating a specific ModelBinder would be fairly simple. I'd
inherit DefaultModelBinder
override the property deserialization with my own
set the binder in my Application_Start using Binders.Add
Seems like with Web Api this is a different process - the System.Web.DefaultModelBinder doesn't have anything to override and that I can't hook things up using Binders.Add. I've tried looking around but couldn't find much on how to actually do what I want. This is further complicated since apparently the ModelBinders api changed quite a bit over Beta and RTM so there's a lot of outdated information out there.
In Web API you have to distinguish three concepts - ModelBinding, Formatters and ParameterBinding. That is quite confusing to people moving from/used to MVC, where we only talk about ModelBinding.
ModelBinding, contrary to MVC, is responsible only for pulling data out of URI. Formatters deal with reading the body, and ParameterBinding (HttpParameterBinding) encompasses both of the former concepts.
ParameterBinding is really only useful when you want to revolutionize the whole mechanism (i.e. allow two objects to be bound from body, implement MVC-style binding and so on) - for simpler tasks modifying binders (for URI specific data) or formatters (for body data) is almost always more than enough.
Anyway, to the point - what you want to achieve can very easily be done with a custom JSON.NET converter (JSON.NET is the default serialization library behind Web API JSON formatting engine).
All you need to do is:
public class Param
{
public int Id { get; set; }
public string Name { get; set; }
[JsonConverter(typeof(CustomArrayConverter))]
public string Choices { get; set; }
}
And then add the converter:
internal class CustomArrayConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return true;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
JsonSerializer serializer)
{
var array = JArray.Load(reader);
return JsonConvert.SerializeObject(array);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, JArray.Parse(value as string));
}
}
In this case we are telling JSON.NET in the converter to store Choices as string (in the read method), and when you return the Param object with the Choices property to the client (in the write method) we take the string and serialize to an array so that the output JSON looks identical to the input one.
You can test it now like this:
public Param PostParam(Param param)
{
return param;
}
And verify that the data coming in is like you wished, and the data coming out is identical to the original JSON.

How do you handle deserializing empty string into an Enum?

I am trying to submit a form from Ext JS 4 to a Spring 3 Controller using JSON. I am using Jackson 1.9.8 for the serialization/deserialization using Spring's built-in Jackson JSON support.
I have a status field that is initially null in the Domain object for a new record. When the form is submitted it generates the following json (scaled down to a few fields)
{"id":0,"name":"someName","status":""}
After submitted the following is seen in the server log
"nested exception is org.codehaus.jackson.map.JsonMappingException: Can not construct instance of com.blah.domain.StatusEnum from String value '': value not one of the declared Enum instance names"
So it appears that Jackson is expecting a valid Enum value or no value at all including an empty string. How do I fix this whether it is in Ext JS, Jackson or Spring?
I tried to create my own ObjectMapper such as
public class MyObjectMapper extends Object Mapper {
public MyObjectMapper() {
configure(DeserializationConfig.Feature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
}
}
and send this as a property to MappingJacksonMappingView but this didn't work. I also tried sending it in to MappingJacksonHttpMessageConverter but that didn't work. Side question: Which one should I be sending in my own ObjectMapper?
Suggestions?
The other thing you could do is create a specialized deserializer (extends org.codehaus.jackson.map.JsonDeserializer) for your particular enum, that has default values for things that don't match. What I've done is to create an abstract deserializer for enums that takes the class it deserializes, and it speeds this process along when I run into the issue.
public abstract class EnumDeserializer<T extends Enum<T>> extends JsonDeserializer<T> {
private Class<T> enumClass;
public EnumDeserializer(final Class<T> iEnumClass) {
super();
enumClass = iEnumClass;
}
#Override
public T deserialize(final JsonParser jp,
final DeserializationContext ctxt) throws IOException, JsonProcessingException {
final String value = jp.getText();
for (final T enumValue : enumClass.getEnumConstants()) {
if (enumValue.name().equals(value)) {
return enumValue;
}
}
return null;
}
}
That's the generic class, basically just takes an enum class, iterates over the values of the enum and checks the next token to match any name. If they do it returns it otherwise return null;
Then If you have an enum MyEnum you'd make a subclass of EnumDeserializer like this:
public class MyEnumDeserializer extends EnumDeserializer<MyEnum> {
public MyEnumDeserializer() {
super(MyEnum.class);
}
}
Then wherever you declare MyEnum:
#JsonDeserialize(using = MyEnumDeserializer.class)
public enum MyEnum {
...
}
I'm not familiar with Spring, but just in case, it may be easier to handle that on the client side:
Ext.define('My.form.Field', {
extend: 'Ext.form.field.Text',
getSubmitValue: function() {
var me = this,
value;
value = me.getRawValue();
if ( value === '' ) {
return ...;
}
}
});
You can also disallow submitting empty fields by setting their allowBlank property to false.
Ended up adding defaults in the EXT JS Model so there is always a value. Was hoping that I didn't have to this but it's not that big of a deal.
I have the same issue. I am reading a JSON stream with some empty strings. I am not in control of the JSON stream, because it is from a foreign service. And I am always getting the same error message. I tried this here:
mapper.getDeserializationConfig().with(DeserializationConfig.Feature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
But without any effect. Looks like a Bug.

Resources