Solr custom query parser "fl" parameter not returning desired result - json

I am currently working on replacing an existing searching platform with Solr. I am new to Solr and currently using Solr Version 6.6.0. Legacy system accepts a JSON object with search parameters. Thus I was asked to implement a custom query parser which accepts a query string in JSON format.
Essentially NO other parameter is passed to Solr except "q" which contains all the required parameters encoded in a JSON formatted string. All the common parameters and local parameters required to execute the query is then extracted by the query parser itself.
This feat was successfully achieved except the "fl" parameter will not give the expecting results. Which means query result composes of all the fields that are present in the document. Code looks like this;
public static final String FIELD_LIST = "fl";
Collection for storing the key value pairs.
HashMap<String,Object> paramMap = new HashMap<String, Object>();
Decoding and formatting the field list.
String ifld = getFieldList();
Parameters are put in the collection thus.
paramMap.put(Constants.FIELD_LIST,ifld);
SolrParams are then generated.
return SolrParams.toSolrParams(new NamedList<>(paramMap));
Each and every query parameter is processed this way and finally in the query parsers parse() method i have this.
//calls the factory method to get the appropriate request type translator
JSONRequestTranslator jrt = (JSONRequestTranslator)JSONQParser.getTranslator(requestType);
//converts the arguments to solrparams.
qstr = jrt.getQueryString();
localParams = jrt.getLocalParams();
params = jrt.getParams();
req.setParams(SolrParams.wrapDefaults(params, this.req.getParams()));
return jrt.parse(qstr, localParams, params, req);
parse() method in classes implementing the JSONRequestTranslator interface looks like this
#Override
public Query parse(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) throws SyntaxError {
return new DisMaxQParser(qstr, localParams, params, req).parse();
}
This works fine but the "fl" parameter seems to have no effect. I don't have a default setting in solrconfig.xml file and while i'm debugging i always find the "fl" parameter set to correct value. I have tried several other approaches like writing custom search component plugins but please explain how to fix this and what am i missing here. Thank you.

Related

PostAsJsonAsync not calling the Controller when <Tvalue> has null fields

My TValue object has foreign key related objects, which has null values when posting; I am having the logic to set the FK objects in the repository. The issue I am facing is that API controller is not getting called when FK objects have all fields null. Please see screenshot. The same code works if I set the value for all but the ID field of the FK objects from the front end.
Is the issue because Json serializer checking for nulls? I have also tried to set the null check ignore option. I am not getting an error on PostAsJsonAsync and the control simply goes to the next line of code
return await result.Content.ReadFromJsonAsync();
without calling the API controller and send an exception
public async Task<SubContract> AddSubContract(SubContract subContract)
{
/* On the injected httpClient, call the PostAsJsonAsync method and pass the subContractObject
* We also need to specifi the api Uri in the parameter list */
JsonSerializerOptions option = new()
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
var result = await httpClient
.PostAsJsonAsync<SubContract>("api/SubContracts", subContract, option);
//Use the content object and ReadFromJsonSync method and typecast it to <SubContract>
return await result.Content.ReadFromJsonAsync<SubContract>();
}
Screenshot
--- Further observations ---
#Serge Thanks for the response. You are right, I am using .Net 6. I have now commented out the nullable but I still have the same issue. Further, I tried to change the function to PostAsync instead of PostAsJsonAsync; below is the new code
// ---- Post Asysc Option -----
var subContractSeralized = JsonSerializer.Serialize(subContract, option);
var stringContent = new StringContent(subContractSeralized,
encoding: System.Text.Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync("api/subcontract", stringContent);
return await response.Content.ReadFromJsonAsync<SubContract>();
I initially thought it was a serialization issue because of the nulls in the nested object but when I debug the new code, I get the below result
subContractSerealized = '{"Id":0,"Name":"Aquatic-Repairs","Status":"In-Progress","WorkTypeId":1002,"WorkType":{"Id":0},"SiteId":3,"Site":{"Id":0},"OrganizationId":3,"Organization":{"Id":0}}'
If you compare this with the Debug screen shot in my first post, you can see that the null value fields in the nested objects are omitted out
Response StatusCode = “Not Found-404”
I am not sure how Response Status code is obtained as the API is not called. I.e. httpClient.PostAsync does not transfer control to the API and my debug breakpoint is not hit.
I tried the same code for an Entity model that has no nested foreign key related objects and it works fine and I am able to add the record to the DB. I have the “Required” validation set on the field properties of the entity models; however, after the API call, I have my repository that is taking care of it. So, I doubt that is an issue. In any case, the code is not even hitting the API and simply returns an 404 NotFound on httpClient.PostAsync.
you must be using Net 6 API, and it causes a validation error. Try to comment Nullable in your API project (your serializer option is not working in this case)
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<!--<Nullable>enable</Nullable>-->
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

How to force DotNetCore 2.1 Web API to output Json format? What library do I need?

I be straight to the point. I am in the process of converting ASP.Net web services into DotNetCore 2.1 services. My question is very simple. How do I get json output from a string (with a GET verb)?
I'm new at this, but almost every piece of documentation and recommendations do not work with DotNetCore.
Obviously, the following will not work:
[HttpGet]
public string Get()
{
return "{\"country_code\":\"US\",\"country_name\":\"United States\",\"region_name\":\"California\",\"city_name\":\"Los Angeles\",\"latitude\":\"34.052230\",\"longitude\":\" - 118.243680\",\"zip_code\":\"90001\",\"time_zone\":\" - 08:00\"}";
}
I just need to convert this string (or tell the client) that I want the output in json. The following does not work either - got a squiggly line under the "Json(" method and, for the life of me, can't find a reference to make it go away (I pulled it from an example, so they must be using a 3rd party json parsing library or there's a reference that I'm missing)
[HttpGet]
public JsonResult Get()
{
return Json("{\"country_code\":\"US\",\"country_name\":\"United States\",\"region_name\":\"California\",\"city_name\":\"Los Angeles\",\"latitude\":\"34.052230\",\"longitude\":\" - 118.243680\",\"zip_code\":\"90001\",\"time_zone\":\" - 08:00\"}", "application/json");
}
Ideally, I'd like to serialize an object to json, but figured I'd start with something ridiculously simple.
Anywho, if anyone can help.
If you don't already have a strongly typed model, you can build an anonymous type and return that from the controller
Simple Example.
public class MyController: Controller {
[HttpGet]
public IActionResult Get() {
var model = new {
country_code = "US",
country_name = "United States",
region_name = "California",
city_name = "Los Angeles",
latitude = 34.052230,
longitude = -118.243680,
zip_code = 90001,
time_zone = "- 08:00"
};
return Ok(model); //200 OK with content
}
}
In more complex scenarios you would get your objects from a data source.
No library needed, the framework out of the box will serialize the object(s) into JSON for you by default unless otherwise configured.
If you insist on passing a manually formatted string then use the ContemntResult object. Pass it the string and the content type.
[HttpGet]
public IActionResult Get() {
string json = "{\"country_code\":\"US\",\"country_name\":\"United States\",\"region_name\":\"California\",\"city_name\":\"Los Angeles\",\"latitude\":\"34.052230\",\"longitude\":\" - 118.243680\",\"zip_code\":\"90001\",\"time_zone\":\" - 08:00\"}";
return Content(json, new MediaTypeHeaderValue("application/json"));
}
Reference Format response data in ASP.NET Core Web API
Forcing a Particular Format
If you would like to restrict the response formats for a specific action you can apply the
[Produces] filter. The [Produces] filter specifies the response
formats for a specific action (or controller). Like most Filters, this
can be applied at the action, controller, or global scope.
[Produces("application/json")]
public class AuthorsController
The [Produces] filter will force all actions within the
AuthorsController to return JSON-formatted responses, even if other
formatters were configured for the application and the client provided
an Accept header requesting a different, available format.
Don't return string but object. So result of your actions are json string this is why you will get string in JSON and not an object
Make sure that your client is sending header "Content-Type": "application/json".
[HttpGet]
public Address Get()
{
return new Address{ CountryCode = "US"} ;
}

My RCP Client is not returning a deep copy of an object

I have been working on an RCP Client to handle weather data.
What i do is 2 things, first i scraped the JSON i will be using and put it into a dart file. See: https://dartpad.dartlang.org/a9c1fe8ce34c608eaa28
My server.dart page, will import the weather data, and then carry out the following:
import "dart:io";
import "weather_data.dart";
import "dart:convert";
import "package:rpc/rpc.dart";
find ApiServer _apiServer = new ApiServer(prettyPrint:true);
main() async {
Weather w = new Weather(WeatherJson);
TestServer ts = new TestServer(w);
_apiServer.addApi(ts);
HttpServer server = await HttperServer.bind(InternetAddress.ANY_IP_V4, 12345);
server.listen(_apiServer.httpRequestHandler);
}
class Weather{
Map weather;
Weather(this.weather){
Map get daily => weather["daily"];
}
}
#ApiClass(name:"test_server", version: 'v1', description: 'This is a test server api to ping for some quick sample data.')
class TestServer {
Weather myWeather;
TestServer(this.myWeather){
}
#ApiMethod(method:'GET', path: 'daily')
Map<String, Object> getDaily(){
return myWeather.daily;
}
}
So, the server starts correctly, and i will go to localhost:12345/test_server/v1/daily and it will return this:
{
"summary": {},
"icon": {},
"data": {}
}
which is not correct. If you look up the JSON data, summary and icon are both strings and data is an array. They are also empty, and should contain the data i wanted to return.
Why does this occur? Is it because i am returning a Map<String, Object>? I was trying to set it up to be: Map<String, dynamic> but the dart compiler didnt like it.
How do i get this data to return the correct dataset?
The Dart website for RPC is located at: https://github.com/dart-lang/rpc
and you can see that under methods, the return value of a method can be either an instance of a class or a future. That makes sense as per usual, so I set it to be a Map<String,Object> though trying to be vague about it by saying: Map was not sufficient.
Edit:
When doing this mostly in dart pad without RPC, it seems to work correctly, by a sample of: https://dartpad.dartlang.org/3f6dc5779617ed427b75
This leads me to believe something is wrong with the Parsing tool as it seems the return type in dartpad allows to return Map, Map<String, Object>, and Map<String, dynamic>.
Having had a quick look at the RPC package README here https://pub.dartlang.org/packages/rpc, it seems that methods marked as Api methods (with #ApiMethod) should return an instance of a class with simple fields such as:
class ResourceMessage {
int id;
String name;
int capacity;
}
The RPC package will take that instance and serialize it into JSON based on the field names.
From the README:
The MyResponse class must be a non-abstract class with an unnamed
constructor taking no required parameters. The RPC backend will
automatically serialize all public fields of the the MyResponse
instance into JSON ...
You are returning a nested Map representation of the JSON you want the RPC operation to emit and would guess that the RPC package does not handle it as you are expecting it to.
Re: this from your question:
This leads me to believe something is wrong with the Parsing tool as
it seems the return type in dartpad allows to return Map, Map, and Map.
There is no 'parsing' on JSON going on on your example. The data you have is a set of nested literal Dart Maps, Lists and Strings with the same structure as the JSON it was derived from. It just happens to look like JSON.
In your example you are just selecting and printing a sub-map of your data map (data['daily']), which prints out the String that results from calling toString() - which is recursive so you get the contents of all the nested maps and lists within it.
So it's not a 'deep copy' issue, but a difference in how toString() and the RPC code processes a set of nested maps.
BTW: the return type of your getDaily() method is immaterial. What is returned is just a Map whatever the declared return type of the method is. Remember types in Dart are optional and there for editors and compilers to spot potentially incorrect code. See https://www.dartlang.org/docs/dart-up-and-running/ch02.html#variables.
I am going to piggyback off of #Argenti Apparatus here as there was a lot of information gained from him.
Long story short, the required return type of the method:
#ApiMethod(method:'GET', path: 'daily')
Map<String,Object> getDaily(){ // <-- Map<String,Object>
return myWeather.daily;
}
is the error.
I went through and updated the method signature to be Map<String,String> and it parsed it entirely correct. It did not parse the object as a string, but actually parsed it as a full recursed object.
I went through and for the sake of code cleanliness also changed signatures of Weather properties to reflect what they actually were, Map<String,Object> as well.
All in all, When defining it to be an value type of Object, it was returning curly braces, but setting it as a String parsed it correctly.
I ran it through JSLint to confirm it is correct as well.
I gave a +1 to the helper, I had to dig deeper into the code to see WHY it wasnt doing a Map correctly.
This also I feel, is plausibly a bug in RPC Dart.

Pass object as parameter in GET request using Google Http Client

I'm using Google Http Client and Jackson to query data to backend (JSON API).
I need to pass parameters (one Java bean object). The object might have few or lot of field. Initially I attempt to pass it as content as follow:
HttpRequest request = requestFactory.buildGetRequest(getUrl(api)).setContent(new JsonCContent(jsonFactory, params));
However, I'm not allowed to set the HTTP content in GET operation.
Any suggestion how can I pass these parameters?
Under one condition:
I don't want to write a util method to convert this object into string of URL parameters. But if there's already reusable API to do it, that would be fine.
I need generic solution if possible. Because I'm going to apply this to 600 JSON API calls.
My last alternative would be to change backend to expect POST request instead of GET, then I perform POST operation on the client side.
Thanks
Instead of extends GenericUrl, you can use GenericUrl.put (inherit from GenericData) to set query parameters. For example:
GenericUrl genericUrl = new GenericUrl("http://yourapi.com/request");
genericUrl.put("user", "user name");
genericUrl.put("token", "token values");
HttpRequest request = requestFactory.buildGetRequest(genericUrl);
It seems like the expected usage is to extend the URL class you are using for your buildGetRequest() call. For instance, let's say you wanted to provide two extra query parameters called "user" and "token". You could do this with the following:
HttpRequest request = requestFactory.buildGetRequest(
new CustomUrl("http://www.yourserver.com").setUser(userId).setToken(token));
where the CustomUrl class is defined as:
public class CustomUrl extends GenericUrl {
public CustomUrl(String encodedUrl) {
super(encodedUrl);
}
#Key("user")
private String mUserId;
#Key("token")
private String mToken;
public CustomUrl setUser(String userId) {
mUserId = userId;
return this;
}
public CustomUrl setToken(String token) {
mToken = token;
return this;
}
}
The values are not necessary for the #Key annotations, but will be used as the name of the respective query parameters if provided. If omitted, the name of the variable will be used instead (see example)
Check google-http-client's javadoc for more info.

Create JSON Request string using Javascript Overlay types in GWT

We have used JSO for our JSON parsing in GWT client side. Now, we need to convert our Java objects to JSON string. I just wanted to understand, how we can achieve this? JSO overlay types was used for JSON parsing. Can it also be used to create a JSON request string or do we have to go by some other means?
Generating a JSON object in JavaScript is pretty simple. You can do it like this:
var obj = { "var1": "hello", "var2": "world" };
this will generate a JSON object with two varibles ("var1" and "var2") with their values ("hello", "world").
The Object can be converted into a String (for sending purposes) with the JSON.stringify(jso); method.
Generating JSON data from the java code isn't possible (well not with a usefull result) since all varibles are optimzed to single Strings, so applying this method wouldn't hava a usefull result (if even possible).
If you have already a JSO object (generated with something like safeeval). You can edit your varibles there, like this:
public final native void newValue(String newValue) /*-{
this.ValueName = newValue;
}-*/;
If you then want the object as string you have to define the following method in your JSO class:
public final native String returnAsString () /*-{
return JSON.stringify(this);
}-*/;
or use this in you Java class: String s = (new JSONObject(jso)).toString();.
This way you can edit your original intput data and send the original object back to the server.
BR