I'm pretty new to Jackson so apologies in advance if there's an obvious solution.
I'm writing a Jersey client and I'm trying to deserialize JSON in the following format:
{
"success": true,
"someEntity": {
"someField": 123
}
}
Now if the 'success' field didn't exist this would be pretty simple as I could just configure the ObjectMapper to use DeserializationFeature.UNWRAP_ROOT_VALUE and it'd deserialize the contents to SomeEntity.
My Response object looks like:
public class Response<T>
{
private boolean success;
private T entity;
public T getEntity()
{
return entity;
}
public boolean isSuccess() {
return success;
}
}
Where entity would be...
public class SomeEntity
{
private int someField;
public int getSomeField()
{
return someField;
}
}
When trying to deserialize the above JSON to Response<SomeEntity> without any configuration I get: Unrecognized field "someEntity" (class Response)
I had some luck with adding #JsonProperty("someEntity") to the entity field but obviously I'd like this response class to be generic and not have to make one for every entity passed to the client.
I'm sure there's a simple solution that I'm not seeing - thanks in advance.
Edit: I've also tried using #JsonTypeInfo to no avail.
Related
I want to set custom error Message for Unrecognized field and others errors with request body.
I tried ExceptionMapper but it dont work :/
Using quarkus and Jackson
public class ReqDTO {
private String a;
}
when send request:
{
"a": "a"
}
its look good. But when send:
{
"a": "a",
"b": "b"
}
have error response:
Unrecognized field "b"; (class ReqDTO), not marked as ignorable
Want customize this message and other bad json body (like too much fields) to own message like "BAD_JSON_SCHEMA".
Tried
#Provider
public class ExHandler implements ExceptionMapper<JsonMappingException>{
public Respone toResponse(JsonMappingException e) {
//response bad field impl
}
}
But its not work. Looks like a json handle exception faster. Tried with "Exception", "JsonParseException" but nothing changed :/
#Path("/")
public class Controller {
#Post
#Consume(APPLICATION_JSON)
#Produces(TEXT_PLAIN)
public Response getA(#Valid ReqDTO reqDTO){
//logic
}
}
#Edit
Found something like DeserializationProblemHandler but dont know how change message for handleUnknownProperty :/
#Singleton
RegisterCustomModuleCustomizer implements ObjectMapperCustomizer {
public void customize(ObjectMapper mapper){
mapper.addHandler(new DeserializationProblemHandler(){
#SneakyThrows
#Override
public boolean handleUnknownProperty(...... params){
throw new ApplicationException("ERRO_BODY_MESS");
}
}
}
}
#Provider
public class ExHandler implements ExceptionMapper<ApplicationException>{
public Respone toResponse(ApplicationException ex) {
return Response.status(BAD_REQUEST).entity(ex.getMessage()).build();
}
}
We have a base class and derived class. When we serialize a derived class, we want only the base class to be serialized. How can we achieve this in ProtoBuf-net.
Edit: new things in v3; the following now works:
[ProtoContract(IgnoreUnknownSubTypes = true)]
public class Foo {}
which does exactly what you want here.
Currently protobuf-net is not very forgiving of unexpected types, because it really wants to be able to round-trip your data. In the 3.0 codebase, this is currently restricted to:
EF proxies, which it detects by the namespace System.Data.Entity.DynamicProxies
NHibernate proxies, which it detects as anything that implements by name NHibernate.Proxy.INHibernateProxy, NHibernate.Proxy.DynamicProxy.IProxy or NHibernate.Intercept.IFieldInterceptorAccessor
I'm open to discussing new additions that could be added to relax this - it would probably need a little discussion, but: it should be possible. Simply adding a marker interface or attribute that the library recognizes as a "ignore this type" token seems pretty reasonable! In fact, as I think about it: it would seem that we could just use [ProtoIgnore] for this, by extending the AttributeTargets for ProtoContractAttribute, and adding a few lines to DynamicStub.ResolveProxies.
Right now, the following "works" (for limited values of "works"), with outputs:
Trying BaseType...
Success; got BaseType
Trying KnownSubTypeViaInclude...
Success; got KnownSubTypeViaInclude
Trying UnknownSubType...
Unexpected sub-type: UnknownSubType
Trying LooksLikeEFProxy...
Success; got BaseType
Trying LooksLikeNHibernateProxy...
Success; got BaseType
code:
using ProtoBuf;
using System;
static class P
{
static void Main()
{
// works, trivially
Try<BaseType>();
// works, processes sub-type
Try<KnownSubTypeViaInclude>();
// fails, unexpected
Try<UnknownSubType>();
// works, processes base type only
Try<System.Data.Entity.DynamicProxies.LooksLikeEFProxy>();
Try<LooksLikeNHibernateProxy>();
}
static void Try<T>() where T : BaseType, new()
{
Console.WriteLine($"Trying {typeof(T).Name}...");
try
{
var clone = Serializer.DeepClone<BaseType>(new T());
Console.WriteLine($"Success; got {clone.GetType().Name}");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
[ProtoContract]
[ProtoInclude(42, typeof(KnownSubTypeViaInclude))]
public class BaseType
{
}
public class KnownSubTypeViaInclude : BaseType { }
public class UnknownSubType : BaseType { }
public class LooksLikeNHibernateProxy : BaseType, NHibernate.Proxy.INHibernateProxy { }
namespace System.Data.Entity.DynamicProxies
{
public class LooksLikeEFProxy : BaseType { }
}
namespace NHibernate.Proxy // let's pretent to be NHibernate
{
public interface INHibernateProxy { }
}
I'm using the [FromQuery] attribute to parse a Get requests arguments into a complex object. For example:
[HttpGet("some-get-request")]
public IActionResult DoSomething([FromQuery] SomeArguments someArgs)
{
}
One of the properties of the SomeArguments object is an enum.
public enum SomeEnum { EnumValue01, EnumValue02 }
public class SomeArguments
{
[FromQuery(Name = "enum_arg")]
public SomeEnum EnumArgument { get; set; }
}
And I call the endpoint with something like:
http://localhost:1234/api/some-controller/some-get-request?enum_arg=EnumValue01
And this all works great. However, I want to be able to use a different enum value in the URL than in my C# enum value. For example, I want to call using a URL such as
http://localhost:1234/api/some-controller/some-get-request?enum_arg=eval01
How can I do this?
I thought I could use the [FromQuery] attribute, like I can with properties, but that doesnt seem to be possible:
'FromQuery' is not valid on this declaration type. It is only valid on 'property, indexer, parameter'
You can use EnumMemberAttribute in conjunction with StringEnumConverter to achieve your goal. Define SomeEnum as following
[JsonConverter(typeof(StringEnumConverter))]
public enum SomeEnum
{
[EnumMember(Value = "eval01")]
EnumValue01,
[EnumMember(Value = "eval02")]
EnumValue02
}
At this point it will work as you need only when Newtonsoft json serializer is used. For example, when controller expects POST request and parameter is marked as [FromBody]. In your case it won't work yet because during binding of [FromQuery] parameter json serializer is not used. To solve this one create custom model binder
public class JsonModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
string rawData = bindingContext.ValueProvider.GetValue(bindingContext.ModelName).FirstValue;
rawData = JsonConvert.SerializeObject(rawData); //turns value to valid json
try
{
SomeEnum result = JsonConvert.DeserializeObject<SomeEnum>(rawData); //manually deserializing value
bindingContext.Result = ModelBindingResult.Success(result);
}
catch (JsonSerializationException ex)
{
//do nothing since "failed" result is set by default
}
return Task.CompletedTask;
}
}
Update SomeEnum definition to use JsonModelBinder
[JsonConverter(typeof(StringEnumConverter))]
[ModelBinder(typeof(JsonModelBinder))]
public enum SomeEnum
This is my client side code to get the string "get-image-data" through RPC calls and getting byte[] from the server.
CommandMessage msg = new CommandMessage(itemId, "get-image-data");
cmain.ivClient.execute(msg, new AsyncCallback<ResponseMessage>() {
#Override
public void onFailure(Throwable caught) {
}
#Override
public void onSuccess(ResponseMessage result) {
if (result.result) {
result.data is byte[].
}
}
});
From the server side I got the length of the data is 241336.
But I could not get the value in onSuccess method. It is always goes to onFailure method.
And I got log on Apache:
com.google.gwt.user.client.rpc.SerializationException: Type '[B' was
not included in the set of types which can be serialized by this
SerializationPolicy or its Class object could not be loaded.
How can I do serialisation in GWT?
1) Create a pojo which implements Serializable interface
Let this pojo has all the data you want in the response of RPC service, in this case image-data
2) Pass this pojo in the response for your RPC service.
The below tutorial has enough information for creating RPC service
http://www.gwtproject.org/doc/latest/tutorial/RPC.html
The objects you transfer to and from the server has to implement IsSerializable.
All your custom Objects within the Object you are transferring also needs to implement IsSerializable.
Your objects cannot have final fields and needs an no argument constructor.
You need getters and setters.
A common serialize object in GWT:
public class MyClass implements IsSerializable {
private String txt;
private MyOtherClass myOtherClass; // Also implements IsSerializable
public MyClass() {
}
public String getTxt() {
return this.txt;
}
public void setTxt(String txt) {
return this.txt = txt;
}
public String getMyOtherClass() {
return this.myOtherClass;
}
public void setMyOtherClass(MyOtherClass myOtherClass) {
return this.myOtherClass = myOtherClass;
}
}
I've created this code:
public class AddonsModule : Ninject.Modules.NinjectModule
{
public override void Load()
{
this.Bind(b => b.FromAssembliesMatching("*")
.SelectAllClasses()
.InheritedFrom(typeof(UIExtensibility.AbstractAddon))
.BindWith(new AddonBindingGenerator())
);
}
private class AddonBindingGenerator : IBindingGenerator
{
public System.Collections.Generic.IEnumerable<Ninject.Syntax.IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(System.Type type, Ninject.Syntax.IBindingRoot bindingRoot)
{
if (type.IsInterface || type.IsAbstract)
yield break;
yield return bindingRoot.Bind(type).ToProvider(typeof(UIExtensibility.AbstractAddon));
}
}
private class AddonProvider : IProvider<UIExtensibility.AbstractAddon>
{
public object Create(IContext context)
{
return null;
}
public Type Type
{
get { throw new NotImplementedException(); }
}
}
}
AddonProvider seems be avoided. This is never performed.
When I perform:
kernel.GetAll<UIExtensibility.AbstractAddon>(), AddonProvider.Create method is never performed.
Could you tell me what's wrong?
I'll appreciate a lot your help.
Thanks for all.
AddOnProvider is inheriting from IProvider<T> instead of UIExtensibility.AbstractAddon.
also, you may have issues binding to private inner classes. make AddOnProvider a public top level class.
You're binding a specific type which inherits from typeof(UIExtensibility.AbstractAddon) to a provider. For example, there could be a class Foo : UIExtensibility.AbstractAddon.
Now your convention binding translates to this:
Bind<Foo>().ToProvider<AddonProvider>();
Now, kernel.GetAll<UIExtensibility.AbstractAddon>() however is looking for bindings made like:
Bind<UIExtensibility.AbstractAddon>().To...
Fix It
So what you need to do is change the line
bindingRoot.Bind(type).ToProvider(new AddonProvider());
to:
bindingRoot.Bind(typeof(UIExtensibility.AbstractAddon)).ToProvider<AddonProvider>();
Furthermore
you're line object f = bindingRoot.Bind(type).ToProvider(new AddonProvider()); is never returning the binding (object f).
does UIExtensibility.AbstractAddon implement IProvider?
Thanks for your answer and comments.
I believe the trouble is on I'm not quite figuring out how this "generic" binding process works.
I'm going to try writing my brain steps process out:
I need to bind every AbstractAddon implementation inside addons assemblies folder. So, I think this code is right, but I'm not sure at all.
this.Bind(b => b.FromAssembliesMatching("*")
.SelectAllClasses()
.InheritedFrom(typeof(UIExtensibility.AbstractAddon))
.BindWith(new AddonBindingGenerator())
);
My AbstractAddon is like:
public abstract class AbstractAddon : IAddon
{
private object configuration;
public AbstractAddon(object configuration)
{
this.configuration = configuration;
}
// IAddon interface
public abstract string PluginId { get; }
public abstract string PluginVersion { get; }
public abstract string getCaption(string key);
public abstract Type getConfigurationPanelType();
public abstract System.Windows.Forms.UserControl createConfigurationPanel();
}
I guess I need to:
foreach implementation of `AbstractAddon` found out,
I need to "inject" a configuration object ->
So, I guess I need to set a provider and provide this configuration object.
This would be my main way of thinking in order to solve this problem.
I've changed a bit my first approach. Instead of using a IBindingGenerator class, I've used the next:
public class AddonsModule : Ninject.Modules.NinjectModule
{
public override void Load()
{
this.Bind(b => b.FromAssembliesMatching("*")
.SelectAllClasses()
.InheritedFrom(typeof(UIExtensibility.AbstractAddon))
.BindAllBaseClasses()
.Configure(c => c.InSingletonScope())
);
this.Bind<object>().ToProvider<ConfigurationProvider>()
.WhenTargetHas<UIExtensibility.ConfigurationAttribute>();
}
So, My ConfigurationProvider is:
private class ConfigurationProvider : IProvider<object>
{
public object Create(IContext context)
{
return "configuration settings";
}
}
And now, my AbstractAddon constructor contains the parameter annotated with ConfigurationAttribute as:
public AbstractAddon([Configuration]object configuration)
{
this.configuration = configuration;
}
The problem now, NInject seems to ignore the configuration object provider. NInject generates a dump object, however, not perform ConfigurationProvider.Create method...
What I'm doing wrong, now?
Is this approach really better than the last one?
Thanks for all.