I tried to use the GET method of api/metrics to retrieve a JSON to use for my program, but the documentation lack to describe all the parameter to use in the requestUrl.
for example in for my program I find, using the Google Chrome console, that the requestUrl is this one:
http://localhost:9000/api/resources?resource=my%3AjavaSample%3AMandria%2Fsrc%2Fmandria%2FIllnessException.java&metrics=new_technical_debt%2Cblocker_violations%2Cburned_budget%2Cbusiness_value%2Cclasses%2Ccomment_lines%2Ccomment_lines_density%2Ccomplexity%2Cclass_complexity%2Cfile_complexity%2Cfunction_complexity%2Cbranch_coverage%2Cnew_it_branch_coverage%2Cnew_branch_coverage%2Cconfirmed_issues%2Ccoverage%2Cnew_it_coverage%2Cnew_coverage%2Ccritical_violations%2Cdirectories%2Cduplicated_blocks%2Cduplicated_files%2Cduplicated_lines%2Cduplicated_lines_density%2Cfalse_positive_issues%2Cpackage_tangles%2Cfiles%2Cfile_complexity_distribution%2Cfunctions%2Cfunction_complexity_distribution%2Cgenerated_lines%2Cgenerated_ncloc%2Cit_branch_coverage%2Cit_coverage%2Cit_line_coverage%2Cit_uncovered_conditions%2Cit_uncovered_lines%2Cinfo_violations%2Cviolations%2Cline_coverage%2Cnew_it_line_coverage%2Cnew_line_coverage%2Clines%2Cncloc%2Clines_to_cover%2Cnew_it_lines_to_cover%2Cnew_lines_to_cover%2Cmajor_violations%2Cminor_violations%2Cnew_blocker_violations%2Cnew_critical_violations%2Cnew_info_violations%2Cnew_major_violations%2Cnew_minor_violations%2Cnew_violations%2Copen_issues%2Coverall_branch_coverage%2Cnew_overall_branch_coverage%2Coverall_coverage%2Cnew_overall_coverage%2Coverall_line_coverage%2Cnew_overall_line_coverage%2Cnew_overall_lines_to_cover%2Coverall_uncovered_conditions%2Cnew_overall_uncovered_conditions%2Coverall_uncovered_lines%2Cnew_overall_uncovered_lines%2Cpackage_cycles%2Cpackage_feedback_edges%2Cpackage_tangle_index%2Cprojects%2Cpublic_api%2Cpublic_documented_api_density%2Cpublic_undocumented_api%2Calert_status%2Creopened_issues%2Csqale_rating%2Cskipped_tests%2Cstatements%2Cteam_size%2Csqale_index%2Csqale_debt_ratio%2Cuncovered_conditions%2Cnew_it_uncovered_conditions%2Cnew_uncovered_conditions%2Cuncovered_lines%2Cnew_it_uncovered_lines%2Cnew_uncovered_lines%2Ctests%2Ctest_execution_time%2Ctest_errors%2Ctest_failures%2Ctest_success_density
is it possible to find a more detailed documentation or the way I try to solve my problem is not the correct one?
Just add &format=json to the parameters.
See http://docs.sonarqube.org/display/SONARQUBE43/Web+Service+API#WebServiceAPI-ResponseFormats
In response to your question how to call from a outside comment:
If you want to call the SonarQube Web Service API from a Java program you can use the Apache HTTP Client:
public static void main(String[] args) throws ClientProtocolException, IOException {
HttpGet httpGet = new HttpGet("http://localhost:9000/api/resources?metrics=lines");
try(CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = httpClient.execute(httpGet);) {
System.out.println(response.getStatusLine());
HttpEntity entity = response.getEntity();
System.out.println(EntityUtils.toString(entity));
}
}
In this case it prints all projects on SonarQube and additionaly the metric "lines". You can add multiple metrics to the list, separated by a comma:
"http://localhost:9000/api/resources?metrics=lines,blocker_violations"
Related
We are using the forge-api-java-client. There is an issue in Model Derivatives getManifest call.
The response fails mapping with a single Message String being returned instead of the expected String Array.
Have switched to using local build of the jar, change in file Message.java to include an alternative constructor for the class setMessage
public void setMessage(String message) {
List<String> messages = new ArrayList<>();
messages.add(message);
setMessage(messages);
}
Could this change be merged into the project.
We'll check it, but as of today, that package is just under maintenance. You are welcome to submit a PR.
I am looking for existing solutions to match dynamic parameters with HttpCore. What I have in mind is something similar to constraints in ruby on rails, or dynamic parameters with sails (see here for example).
My objective is to define a REST API where I could easily match requests like GET /objects/<object_id>.
To give a little bit of context, I have an application that creates an HttpServer using the following code
server = ServerBootstrap.bootstrap()
.setListenerPort(port)
.setServerInfo("MyAppServer/1.1")
.setSocketConfig(socketConfig)
.registerHandler("*", new HttpHandler(this))
.create();
And the HttpHandler class that matches the requested URI and dispatches it to the corresponding backend method:
public void handle(final HttpRequest request, final HttpResponse response, final HttpContext context) {
String method = request.getRequestLine().getMethod().toUpperCase(Locale.ROOT);
// Parameters are ignored for the example
String path = request.getRequestLine().getUri();
if(method.equals("POST") && path.equals("/object/add") {
if(request instanceof HttpEntityEnclosingRequest) {
addObject(((HttpEntityEnclosingRequest)request).getEntity())
}
[...]
For sure I can replace path.equals("/object/add") by something more sophisticated with RegEx to match these dynamic parameters, but before doing so I'd like to know if I am not reinventing the wheel, or if there is an existing lib/class I didn't see in the docs that could help me.
Using HttpCore is a requirement (it is already integrated in the application I am working on), I know some other libraries provide high-level routing mechanisms that support these dynamic parameters, but I can't really afford switching the entire server code to another library.
I am currently using httpcore 4.4.10, but I can upgrade to a newer version of this might help me.
At present HttpCore does not have a fully featured request routing layer. (The reasons for that are more political than technical).
Consider using a custom HttpRequestHandlerMapper to implement your application specific request routing logic.
final HttpServer server = ServerBootstrap.bootstrap()
.setListenerPort(port)
.setServerInfo("Test/1.1")
.setSocketConfig(socketConfig)
.setSslContext(sslContext)
.setHandlerMapper(new HttpRequestHandlerMapper() {
#Override
public HttpRequestHandler lookup(HttpRequest request) {
try {
URI uri = new URI(request.getRequestLine().getUri());
String path = uri.getPath();
// do request routing based on the request path
return new HttpFileHandler(docRoot);
} catch (URISyntaxException e) {
// Provide a more reasonable error handler here
return null;
}
}
})
.setExceptionLogger(new StdErrorExceptionLogger())
.create();
Spring Boot Actuator's Trace does a good job of capturing input/output HTTP params, headers, users, etc. I'd like to expand it to also capture the body of the HTTP response, that way I can have a full view of what is coming in and going out of the the web layer. Looking at the TraceProperties, doesn't look like there is a way to configure response body capturing. Is there a "safe" way to capture the response body without messing up whatever character stream it is sending back?
Recently, I wrote a blog post about customization of Spring Boot Actuator's trace endpoint and while playing with Actuator, I was kinda surprised that response body isn't one of the supported properties to trace.
I thought I may need this feature and came up with a quick solution thanks to Logback's TeeFilter.
To duplicate output stream of the response, I copied and used TeeHttpServletResponse and TeeServletOutputStream without too much examination.
Then, just like I explained in the blog post, extended WebRequestTraceFilter like:
#Component
public class RequestTraceFilter extends WebRequestTraceFilter {
RequestTraceFilter(TraceRepository repository, TraceProperties properties) {
super(repository, properties);
}
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
TeeHttpServletResponse teeResponse = new TeeHttpServletResponse(response);
filterChain.doFilter(request, teeResponse);
teeResponse.finish();
request.setAttribute("responseBody", teeResponse.getOutputBuffer());
super.doFilterInternal(request, teeResponse, filterChain);
}
#Override
protected Map<String, Object> getTrace(HttpServletRequest request) {
Map<String, Object> trace = super.getTrace(request);
byte[] outputBuffer = (byte[]) request.getAttribute("responseBody");
if (outputBuffer != null) {
trace.put("responseBody", new String(outputBuffer));
}
return trace;
}
}
Now, you can see responseBody in the JSON trace endpoint serves.
From one of the spring maintainers:
Tracing the request and response body has never been supported out of the box. Support for tracing parameters was dropped as, when the request is POSTed form data, it requires reading the entire request body.
https://github.com/spring-projects/spring-boot/issues/12953
With a webflux reactive stack, it is possible to capture http request and response body using spring-cloud-gateway and inject them into actuator httptrace by defining a custom HttpTraceWebFilter.
See full associated code at https://gist.github.com/gberche-orange/06c26477a313df9d19d20a4e115f079f
This requires quite a bit of duplication, hopefully springboot team will help reduce this duplication, see related https://github.com/spring-projects/spring-boot/issues/23907
I have a rest webservice (with jersey) which returns json list, if i call it directly it returns exactly this :
[{"success":false,"uri":"foo:22","message":"Unknown host : foo"},{"success":true,"uri":"localhost:8082","message":null}]
generated by this snippet :
#GET
#Path("/opening/")
public List<OpeningResult> testOpenings(#QueryParam("uri") List<String> uris) {
LOG.debug("testOpenings request uris :[" + uris + "]");
List<OpeningResult> openingResults = infoService.testOpenings(uris);
return openingResults;
}
It's a Collection of Pojo which look like this :
#XmlRootElement(name = "OpeningResult")
public class OpeningResult {
attributes
...
getter/setter
}
this Pojo is shared through a common jar between the server and the client.
i call the web service with this snippet :
Client client = Client.create();
WebResource resource = client.resource("http://localhost:8080/scheduler/rest/opening");
MultivaluedMap<String, String> params = new MultivaluedMapImpl();
for (String uri : uris) {
params.add("uri", uri);
}
List<OpeningResult> results = newArrayList(resource.queryParams(params).get(OpeningResult[].class));
I add some trace on the server side, i see that my rest service is called with the good parameters, buth on client side, i have this error :
Caused by: javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"success"). Expected elements are <{}OpeningResult>
I don't find where it comes from ?
Modify your code to set up your client like this:
ClientConfig clientConfig = new DefaultClientConfig();
clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, true);
Client client = Client.create(clientConfig);
I had the exact same problem until this question and its answers pointed me in the right direction.
The situation is caused by the default jersey-json module used for serialization to and from JSON, which does not handle certain JSON constructs properly.
You can set the FEATURE_POJO_MAPPING flag to use the Jackson library's JacksonJsonProvider for JSON serialization instead.
Check out the Jersey Client side doc on using JSON. It looks like you're at least missing the annotation:
#Produces("application/json")
But you could also be missing the POJO Mapping feature filters for both client and server side. These all seem to be minor configuration changes.
I am using Spring 3.0.6 and i have a single controller for uploading files to the server. I am using a script to upload using XmlHttpRequest for browsers that support it while the rest of the browsers submit a (hidden) multipart form. The problem however is that when a form is submitted it sends the following header:
Accept text/html, application/xhtml+xml, */*
I figure that due to this header the Controller which is marked with #ResponseBody replies with the response been converted to XML instead of JSON. Is there a way to get around this without hacking the form submit request?
You can force JSON using #RequestMapping(produces = "application/json"). I don't remember if this is available in 3.0 but it is available in 3.1 and 3.2 for sure.
As others noted, Jackson needs to be on your classpath.
Thank you! I was having exactly the same issue and your post resolved my problem.
On the UI I'm using JQuery with this file upload plugin:
https://github.com/blueimp/jQuery-File-Upload/wiki
Here's my completed method (minus the biz logic):
#RequestMapping(value = "/upload", method = RequestMethod.POST)
public void handleUpload( #RequestParam("fileToUpload") CommonsMultipartFile uploadFile, ServletResponse response){
List<UploadStatus> status = new ArrayList<UploadStatus>();
UploadStatus uploadStatus = new UploadStatus();
status.add(uploadStatus);
if(uploadFile == null || StringUtils.isBlank(uploadFile.getOriginalFilename())){
uploadStatus.setMessage(new Message(MessageType.important, "File name must be specified."));
}else{
uploadStatus.setName(uploadFile.getOriginalFilename());
uploadStatus.setSize(uploadFile.getSize());
}
ObjectMapper mapper = new ObjectMapper();
try {
JsonGenerator generator = mapper.getJsonFactory().createJsonGenerator(response.getOutputStream(), JsonEncoding.UTF8);
mapper.writeValue(generator, status);
generator.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
If you want a JSON response, you can easily accomplish that by having the Jackson JARs on your classpath. Spring will auto-magically pick up on them being there and will convert your #ResponseBody to JSON.
I made it work by getting rid off #ResponseBody and instead doing manually the conversion (always using Jackson), i.e.
Response r = new Response();
ObjectMapper mapper = new ObjectMapper();
JsonGenerator generator = mapper.getJsonFactory().createJsonGenerator(response.getOutputStream(), JsonEncoding.UTF8);
try {
File f = uploadService.getAjaxUploadedFile(request);
r.setData(f.getName());
} catch (Exception e) {
logger.info(e.getMessage());
r = new Response(new ResponseError(e.getMessage(), ""));
}
mapper.writeValue(generator, r);
generator.flush();
Does anyone know another way? I tried setting up a ContentNegotiatingViewResolver but i don't want to break any other controllers by assigning all hmtl to json. Also, i tried to do it for this method only via a custom viewresolver but when i setup a jsonview and use BeanNameViewResolver although the response is correctly converted to JSON the server throws an
HttpRequestMethodNotSupportedException: exception, with Request method 'POST' not supported and set status to 404.