I have some JSON, which contains a key named "type". This key can have the value include or exclude. I want to configure Gson to not deserialize the Json, and create an object when the key value is exclude.
I realize I can write a custom deserializer, check for the appropriate, and create the object or not. However, I was not sure if there was another way using some type of exclusion strategy.
The example I outlined is over-simplified. My real JSON contains many more fields.
// Deserialize me
{
"type" : "include"
}
// Skip over me, and do not deserialize
{
"type" : "exclude"
}
I don't think the ExclusionStrategy can help here. It works with classes rather than instances and at the time instances get processed there's just a result of its evaluation present (in case you want to have a look at the code, see ReflectiveTypeAdapterFactory.BoundField).
This might help you...
Gson gson = new Gson();
JsonObject jsonObj = gson.fromJson (jsonStr, JsonElement.class).getAsJsonObject();
// Just read the required field
if(jsonObj.get("type").getAsString().equals("include")) {
// Continue parsing/deserializing other details
} else {
// Skip
}
You can refer this for Gson API documentation
Related
I am using MapStruct to convert a Page object to a custom object of my application. I am using this mapping in order to convert the content field of the Page object to a list of custom objects found in my data model:
#Mapping(target = "journeys", source = "content")
While this works OK and does convert the elements when content is present, this does not work correctly in case of no Page content. Taking a look at the code seems to show that the following check is added in the generated mapper class:
if ( page.hasContent() ) {
List<JourneyDateViewResponseDto> list = page.getContent();
journeyDateViewPageResponseDto.setJourneys( new ArrayList<JourneyDateViewResponseDto>( list ) );
}
When this is added the mapping action of the inner objects is omitted, meaning that I end up with a null list. I am not really sure as to why and how this check is added but I would like to find a way of disabling it and simply end up with an empty list of elements. Is there a way this can be done using MapStruct?
MapStruct has the concept of presence checkers (methods that have the pattern hasXXX). This is used to decide if a source property needs to be mapped.
In case you want to have a default value in your object I would suggest making sure that your object is instantiated with an empty collection or provide an #ObjectFactory for your object in which you are going to set the empty collection.
e.g.
Default value in class
public class JourneyDateViewPageResponseDto {
protected List<JourneyDateViewResponseDto> journeys = new ArrayList<>();
//...
}
Using #ObjectFactory
#Mapper
public interface MyMapper {
JourneyDateViewPageResponseDto map(Page< JourneyDateViewResponseDto> page);
#ObjectFactory
default JourneyDateViewPageResponseDto createDto() {
JourneyDateViewPageResponseDto dto = new JourneyDateViewPageResponseDto();
dto.setJourneys(new ArrayList<>());
return dto;
}
}
#Mapping(target = "journeys", source = "content", defaultExpression = "java(java.util.List.of())")
When I use the Elasticsearch.Net client to do a Get document request, I am setting _source to false and specifying the stored fields I want to return. I do not want the _source because there are large contents and even if I exclude them, the server still loads the source into memory to parse it which is very slow and I do not want.
When I do have source included, I can just specify the object type and it is automatically de-serialized from the _source. How can I do this with the Fields property? It is of type FieldValues : IsADictionaryBase<string, LazyDocument>
var response = await client.GetAsync<MyObject>(docId,
s => s.Index(myIndex)
.SourceEnabled(false)
.StoredFields(new string[] {
"MyStringArray1",
"MyStringArray2",
"MyLongValue" }
));
The only way I have found to do this is to iterate over all the properties in the object manually.
MyObject mine = new MyObject()
{
MyStringArray1 = response.Fields["MyStringArray1"].As<string[]>(),
MyStringArray2 = response.Fields["MyStringArray2"].As<string[]>(),
MyLongValue = response.Fields.Value<long>("MyLongValue")
};
Is there an easier way to deserialize to MyObject type?
I'm trying to learn Painless so that I could use it while trying to enrich and manipulate incoming documents. However, every way I've seen for accessing the document just results in errors.
Having input this in the Painless Lab in Kibana, these are the errors I'm getting:
def paths = new String[3];
paths[0]= '.com';
paths[1] = 'bar.com';
paths[2] = 'foo.bar.com';
doc['my_field'] = paths; // does not work: '[Ljava.lang.String; cannot be cast to org.elasticsearch.index.fielddata.ScriptDocValues'
ctx.my_field = paths; // does not compile: 'cannot resolve symbol [ctx.my_field]'
return doc['my_field'] == 'field_value'; // does not work: 'No field found for [my_field] in mapping'
doc['my_field'] == 'field_value' complains despite the field being present in the test document, though doc.containsKey('my_field') does return false.
How should I actually be accessing and manipulating the incoming document? I'm using ElasticSearch 7.12.
You can create ingest pipeline with set processor for adding hardcode value to incoming document.
{
"description" : "sets the value of count to 1",
"set": {
"field": "count",
"value": 1
}
}
There are very specific context available for painless API. you are using String[] which may be causing issue so you need to use either Arrays or ArraysList. you can check example of painless lab here.
Below is script i have tried in painless lab and it is working as expcted:
def ctx = params.ctx;
ArrayList paths = new ArrayList();
paths.add('.com');
paths.add('bar.com');
paths.add('foo.bar.com');
ctx['my_field'] = paths;
return ctx
Add below in parameters tab, i missed to add this in answer. this required because in actual implmentation you will get value from context and update context.
{
"ctx":{
"my_field":["test"]
}
}
#RequestMapping(value = "/**", consumes = MediaType.ALL_VALUE)
#ResponseBody
public Object mirror(HttpServletRequest req, #Nullable #RequestBody Map<String, String> form) {
...
}
I just want the plain key and value for all form data entries here but it also includes query parameters in the map.
I need to be able to tell the difference between what came from the form and what came from the query.
Getting the query parameters separately is easily done using URI parsing but it's not so easy to remove the query parameters from the form map. Especially in the case they have the same keys.
Changing the parameter to MultiValueMap adds values with the same key into an array. Using just a Map causes the query parameters to overwrite the form data with equal keys.
I found where this is happening, for the MockHttpServletRequest at least: buildRequest method:
String query = this.url.getRawQuery();
if (!this.queryParams.isEmpty()) {
String s = UriComponentsBuilder.newInstance().queryParams(this.queryParams).build().encode().getQuery();
query = StringUtils.isEmpty(query) ? s : query + "&" + s;
}
if (query != null) {
request.setQueryString(query);
}
addRequestParams(request, UriComponentsBuilder.fromUri(this.url).build().getQueryParams());
this.parameters.forEach((name, values) -> {
for (String value : values) {
request.addParameter(name, value);
}
});
It's combining the form data and query data into one map. So is there an alternative way to parse the form data ONLY or exclude query params from the map!?
From the javadoc for #RequestParam:
In Spring MVC, "request parameters" map to query parameters, form data, and parts in multipart requests. This is because the Servlet API combines query parameters and form data into a single map called "parameters", and that includes automatic parsing of the request body.
Not sure if there's a more elegant way, but you could possibly use Spring's UriComponentsBuilder class to parse the URI string and get back the query parameters.
Using ElasticSearch.Net v6.0.2
Given the Indexed item
{
"PurchaseFrequency": 76,
"purchaseFrequency": 80
}
and the POCO Object
public class Product
{
public int PurchaseFrequency { get; set; }
}
and the setting
this.DefaultFieldNameInferrer(x => x);
Nest is returning a PurchaseFrequency = 80 even though this is the wrong field.
How can I get NEST to pull the correct cased field from ElasticSearch?
I don't think that this is going to be easily possible because this behaviour is defined in Json.NET, which NEST uses internally (not a direct dependency in 6.x, it's IL-merged into the assembly).
For example,
JsonConvert.DeserializeAnonymousType("{\"a\":1, \"A\":2}", new { a = 0 })
deserializes the anonymous type property a value to 2. But
JsonConvert.DeserializeAnonymousType("{\"A\":2, \"a\":1}", new { a = 0 })
deserializes the anonymous type property a value to 1 i.e. the order of properties as they appear in the returned JSON has a bearing on the final value assigned to a property on an instance of a type.
If you can, avoid JSON property names that differ only in case. If you can't, then you'd need to hook up the JsonNetSerializer in the NEST.JsonSerializer nuget package and write a custom JsonConverter for your type which only honours the exact casing expected.