field missing in the json response spring boot - json

I have Stock response class with only two fields as follows
class StockResponse {
private String orderId;
private String status;
//constructor
//getters and setters
}
and the also the controller as follows
#RestController
#RequestMapping("/stocks")
public class StockController {
private static List<StockResponse> stocktList = new ArrayList <StockResponse > ();
static {
stocktList.add(new StockResponse("order1", "AVAILABLE"));
stocktList.add(new StockResponse("order2", "AVAILABLE"));
stocktList.add(new StockResponse("order3", "NOT AVAILABLE"));
stocktList.add(new StockResponse("order4", "AVAILABLE"));
}
#GetMapping("/")
public ResponseEntity < ? > getProsucts() {
return ResponseEntity.ok(stocktList);
}
#GetMapping(path="/{id}", produces = "application/json;charset=UTF-8")
public StockResponse getProsucts(#PathVariable String id) {
StockResponse product = findOrder(id);
if (product == null) {
// return ResponseEntity.badRequest(product)
// .body("Invalid product Id");
}
System.out.println(product.getOrderId());
System.out.println(product.getStatus());
return new StockResponse(product.getOrderId(), product.getStatus());
}
private StockResponse findOrder(String id) {
return stocktList.stream()
.filter(user -> user.getOrderId()
.equals(id))
.findFirst()
.orElse(null);
}
}
when I make a call to the localhost:8082/stocks/order1 I get a response with only one field showing up as follows
what could I be missing out?

I am unable to reproduce this, meaning it works for me.
Listing all stocks
$ curl -sS 'http://localhost:8080/stocks/' | jq "."
[
{
"orderId": "order1",
"status": "AVAILABLE"
},
{
"orderId": "order2",
"status": "AVAILABLE"
},
{
"orderId": "order3",
"status": "NOT AVAILABLE"
},
{
"orderId": "order4",
"status": "AVAILABLE"
}
]
Getting specific stock
$ curl -sS 'http://localhost:8080/stocks/order1' | jq "."
{
"orderId": "order1",
"status": "AVAILABLE"
}
My StockController is identical to yours. I also copy and pasted your StockResponse to get the field names identical to yours, but since you didn't include the constructor/getter and setter I'll show the one which works for me.
The way you're instantiating the StockResponse objects in the stocktList list is using the constructor and that might point to that you're not actually setting the this.status on the objects. If that doesn't work, double check that the getter for the status field is actually called getStatus().
public class StockResponse {
private String orderId;
private String status;
public StockResponse(String orderId, String status) {
this.orderId = orderId;
this.status = status;
}
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
The fact that your response contains a field that uses "non-standard" upper case for the first letter tells me that maybe you're doing something else that's not standard the might influence your result.

I ensured that all my getters and setters are public,
I looked closely and I had missed public on
public String getStatus()

Related

Serialize Feign Json Response to object

I've the following Json response coming from a Feign client:
{
"maxResults": 1,
"total": 5,
"isLast": false,
"values": [
{
"id": 37,
"self": "https://your-domain.atlassian.net/rest/agile/1.0/sprint/23",
"state": "active",
"name": "sprint 1",
"goal": "sprint 1 goal"
}
]
}
The feign client:
#FeignClient(name = "jira")
public interface JiraFeignClient {
#GetMapping("/rest/agile/1.0/board/{boardId}/sprint?state=active&maxResults=1")
ActiveSprintResponse getActiveSprint(#PathVariable String boardId);
}
I'd like to define the ActiveSprintResponse class in order to have the information related to the "values" property (I'm only interested in those) of the json response but I don't understand how can I easily represent it.
I would have no problems for the properties "maxResults", "total" etc... but how can easily unpack "values"? I can assume I will always have only one element in the value array.
I've tried defining it like that but it clearly does not work:
public class ActiveSprintResponse {
private final String id;
private final String self;
private final String name;
private final String goal;
public ActiveSprintResponse(String id, String self, String name, String goal) {
this.id = id;
this.self = self;
this.name = name;
this.goal = goal;
}
}
You need to define a class that represents the root JSON object. You can define a property for the values of type List then:
public class ActiveSprintResponseList {
private List<ActiveSprintResponse> values;
// (Other fields omitted for simplicity)
public void setValues(List<ActiveSprintResponse> values) {
this.values = values;
}
public List<ActiveSprintResponse> getValues() {
return values;
}
}
you then need to declare that class as return type:
#FeignClient(name = "jira")
public interface JiraFeignClient {
#GetMapping("/rest/agile/1.0/board/{boardId}/sprint?state=active&maxResults=1")
ActiveSprintResponseList getActiveSprint(#PathVariable String boardId);
}
and use it on the calling side:
ActiveSprintResponseList response = client.getActiveSprint(..);
List<ActiveSprintResponse> values = response.getValues();
// work with values

Post nested Json to spring controller using Jackson data binding

Well I am trying to retrieve a nested json in spring controller and getting "The request sent by the client was syntactically incorrect."
My code is working and getting the correct data binding if I don't do nested json format, so I can conclude that maybe something is not right in my DTO.
CURL Command:
CURL -i -H "Content-Type: application/json" -X POST http://localhost:8080/insertMapping -d '{"mapping": {"adobe_segment_id": "125", "dp_key_id": "1"}, "type": "adobe"}'
JSON:
{"mapping": {"adobe_segment_id": "125", "dp_key_id": "1"}, "type": "adobe"}
Controller:
#RequestMapping(value = "/insertMapping", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> createUser(#RequestBody RequestBodyDTO mapping) {
LOG.info("/insertMapping" + " ,type:" + mapping.getType().getType());
return null;
}
RequestBodyDTO:
public class RequestBodyDTO {
private MappingDTO mapping;
private TypeDTO type;
public TypeDTO getType() {
return type;
}
public void setType(TypeDTO type) {
this.type = type;
}
public MappingDTO getMapping() {
return mapping;
}
public void setMapping(MappingDTO mapping) {
this.mapping = mapping;
}
}
MappingDTO:
public class MappingDTO {
// adobe
private Integer adobe_segment_id;
private Integer dp_key_id;
public Integer getAdobe_segment_id() {
return adobe_segment_id;
}
public void setAdobe_segment_id(Integer adobe_segment_id) {
this.adobe_segment_id = adobe_segment_id;
}
public Integer getDp_key_id() {
return dp_key_id;
}
public void setDp_key_id(Integer dp_key_id) {
this.dp_key_id = dp_key_id;
}
}
TypeDTO:
public class TypeDTO {
private String type;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
Problem resolved after I changed "private TypeDTO type" to "private String type".

DeserializeObject Json

I have the following json data and i need to deserialize it. Btw i am using C# and i tried the following:
C#
// the data has been assigned to json variable
Result deserializedResult = JsonConvert.DeserializeObject<Result>(json);
Result class
private String _id = String.Empty;
private String[] _result = { };
private String _error = String.Empty;
public Result()
{
}
public String id
{
get { return _id; }
set { _id = value; }
}
public String[] result
{
get { return _result; }
set { _result = value; }
}
public String error
{
get { return _error; }
set { _error = value; }
}
JSon
{"id":1,"result":
[
{"id":12345,
"list_id":54321,
"is_test":false,
"type":"manual",
"creator_name":"Test Solutions"
},
{"id":54321,
"list_id":12345,
"is_test":false,
"type":"manual",
"creator_name":"Test Solutions"
}
],
"error":null}
ERROR
Additional information: Error reading string. Unexpected token: StartObject. Path 'result[0]', line 1, position 19.
I was missing something so obvious. Instead of another object e.g. Result class i was expecting an array. I fixed the issue editing Result property chaning
public String[] result { get; set; }
to
public List<Result> result { get; set; }
Thank you and sorry for bothering. Have a nice day

Jackson in Spring: how to unmarshal a "generic" class w/o it thinking it's a LinkedHashMap?

So my entities look like this:
public class HappyClass<T>
{
private String id;
prviate int ver;
private Object obj;
public String getId()
{
return this.id;
}
public void setId( String id )
{
this.id = id;
}
public int getVer()
{
return this.ver;
}
public void setVer( int ver )
{
this.ver = ver;
}
#JsonTypeInfo( use = Id.NONE )
public T getObj()
{
return obj;
}
public void setObj( T obj )
{
this.obj = obj;
}
}
public class HappyGeneric
{
private String someStuff();
public String getSomeStuff()
{
return this.someStuff();
}
public void setSomeStuff( String someStuff )
{
this.someStuff = someStuff;
}
}
If I instantiate a class like this:
HappyClass<HappyGeneric> hc = new HappyClass<HappyGeneric>();
If I send it to Spring in a #ResponseBody it returns this:
{
"id" : "iamsomeid",
"ver" : 123,
"obj" : {
"someStuff" : "iamsomestuff"
}
}
However, when Spring and/or Jackson attempts to unmarshal the same JSON, it figures out that the main class is a HappyClass, however, the getObj() it unmarshals to a LinkedHashMap and not a HappyGeneric no matter what I seem to annotate it with.
Anybody have any ideas how I can force Jackson to unmarshal that generic to the original class?
Thanks!
EDIT: I'm aware I can call mapper.convertValue( blah.getObj(), HappyGeneric.class ) and get the object out that way-- I was hoping to get Spring to figure it out automatically (through annotations, for example).

WCF Data Services 5.0 Workaround for returning POCOs?

I'm pretty sure it hasn't, but apologies if this question has already been asked. And additional apologies if this is just flat out a dumb question but I feel like I'm either completely missing something or have the right idea and just need some backup for my own sanity.
I've been implementing WCF Data Services 5.0 in our application and am having no issues with read operations returning entity objects.
Unfortunately there is that nasty limitation when it comes to service operations that they can only return primitive types (See MSDN). It's very annoying given that it has no problems with the entity objects.
I know that one workaround is to create a "dummy" complex type since WCFDS will recognize that but I don't want to just throw random POCOs into my data model that aren't actually in the database.
So the solution that occurred to me was to create an extension method for my objects that can serialize them into JSON strings to be returned by the service. My question is; are there any compelling arguments why I shouldn't do this or can anyone suggest any better alternatives?
Edit: Additional information to clarify my current issues
I created a very simple example of what I'm doing that originally raised this question. My service class follows first:
[JsonpSupportBehavior]
public partial class SchedulingService : DataService<ChronosDataContext>, ISchedulingService
{
public static void InitializeService(DataServiceConfiguration config)
{
#if DEBUG
config.UseVerboseErrors = true;
#endif
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
config.SetServiceOperationAccessRule(
"TestService",
ServiceOperationRights.All);
}
[WebGet]
public SchedulingResult TestService(
string testParam1,
string testParam2)
{
// NOTE: I never use the params, they're just there for this example.
SchedulingResult result = SchedulingResult.Empty;
result.Status = OperationStatus.Success;
result.ResponseID = Guid.NewGuid();
result.AffectedIDs = new List<int>(new int[] { 1, 2, 3, 4, 5, 6, 7 });
result.RecordsAffected = 10;
return result;
}
}
Attempting to access this service using my browser, I get the following request error:
The server encountered an error processing the request. The exception message is
'Unable to load metadata for return type
'Chronos.Services.SchedulingResult' of method
'Chronos.Services.SchedulingResult TestService(System.String, System.String)'.'.
See server logs for more details.
The exception stack trace is:
at System.Data.Services.Providers.BaseServiceProvider.AddServiceOperation(MethodInfo method, String protocolMethod)
at System.Data.Services.Providers.BaseServiceProvider.AddOperationsFromType(Type type)
at System.Data.Services.Providers.BaseServiceProvider.LoadMetadata()
at System.Data.Services.DataService`1.CreateMetadataAndQueryProviders(IDataServiceMetadataProvider& metadataProviderInstance, IDataServiceQueryProvider& queryProviderInstance, BaseServiceProvider& builtInProvider, Object& dataSourceInstance)
at System.Data.Services.DataService`1.CreateProvider()
at System.Data.Services.DataService`1.HandleRequest()
at System.Data.Services.DataService`1.ProcessRequestForMessage(Stream messageBody)
at SyncInvokeProcessRequestForMessage(Object , Object[] , Object[] )
at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage41(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage3(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage2(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage1(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
Below are the classes that make up the SchedulingResult that I'm trying to return:
public class SchedulingResult : ServiceInvocationResponse
{
public SchedulingResult()
: base()
{
this.Payload = new object[]
{
new List<int>(),
new List<int>()
};
}
public List<int> AffectedIDs
{
get { return (List<int>)Payload[0]; }
set { Payload[0] = value; }
}
public List<int> FailedIDs
{
get { return (List<int>)Payload[1]; }
set { Payload[1] = value; }
}
public static SchedulingResult Empty
{
get { return new SchedulingResult(); }
}
}
public class ServiceInvocationResponse : AbstractJsonObject<ServiceInvocationResponse>
{
public ServiceInvocationResponse()
{
this.Status = OperationStatus.Unknown;
this.Severity = ErrorSeverity.None;
}
public virtual int RecordsAffected { get; set; }
public virtual Exception ErrorObject { get; set; }
internal virtual object[] Payload { get; set; }
}
public abstract class AbstractJsonObject<TBaseType>
{
public virtual object Deserialize(string source)
{
return JsonConvert.DeserializeObject(source);
}
public virtual T Deserialize<T>(string source)
{
return JsonConvert.DeserializeObject<T>(source);
}
public string Serialize()
{
return JsonConvert.SerializeObject(
this, Formatting.Indented);
}
public override string ToString()
{
return this.Serialize();
}
public static TBaseType FromString(string json)
{
return JsonConvert.DeserializeObject<TBaseType>(json);
}
}
It is possible to return one or many primitive, complex, or entity types from a service operation.
A primitive type is what you'd expect: string, int, bool, etc.
A complex type is a class that doesn't have a unique key (a property named ID or the [DataServiceKey("<yourkeyhere>")] attribute)
An entity type is a class that does have a unique key
For instance:
using System.Data.Services;
using System.Data.Services.Common;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Web;
namespace Scratch.Web
{
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class ScratchService : DataService<ScratchContext>
{
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.SetServiceOperationAccessRule("*", ServiceOperationRights.AllRead);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
config.UseVerboseErrors = true;
}
[WebGet]
public string GetPrimitive()
{
return "Success";
}
[WebGet]
public IQueryable<string> GetPrimitives()
{
return new[] { "Success", "Hello World" }.AsQueryable();
}
[WebGet]
public ComplexType GetComplexType()
{
return new ComplexType { Property1 = "Success", Property2 = "Hello World" };
}
[WebGet]
public IQueryable<ComplexType> GetComplexTypes()
{
return new[] {
new ComplexType { Property1 = "Success", Property2 = "Hello World" },
new ComplexType { Property1 = "Success", Property2 = "Hello World" }
}.AsQueryable();
}
[WebGet]
public EntityType GetEntityType()
{
return new EntityType { Property1 = "Success", Property2 = "Hello World" };
}
[WebGet]
public IQueryable<EntityType> GetEntityTypes()
{
return new[] {
new EntityType { Property1 = "Success1", Property2 = "Hello World" },
new EntityType { Property1 = "Success2", Property2 = "Hello World" }
}.AsQueryable();
}
}
public class ScratchContext { }
public class ComplexType
{
public string Property1 { get; set; }
public string Property2 { get; set; }
}
[DataServiceKey("Property1")]
public class EntityType
{
public string Property1 { get; set; }
public string Property2 { get; set; }
}
}
Perhaps you're running into some other problem?