I want to use camel json schema validator in order to validate a JSON file with a JSON schema using draft 07 .
Apache Camel uses draft 04 by default and in order to change it to draft 07 I have to use a schemaLoader of type JsonSchemaLoader according to its documentation.
How to use the schemaLoader correctly ?? I followed this solution and Apache Camel logs :
JsonSchemaException: Validation: null is an invalid segment for URI
Here is what we are using on our Camel-3 project (and which is working fine):
public class MyFactory {
#Produces
#ApplicationScoped
#Named("my-schema")
public final JsonSchemaLoader createJsonSchemaLoader() {
return (camelContext, schemaStream) -> {
SchemaValidatorsConfig conf = new SchemaValidatorsConfig();
conf.setJavaSemantics(true);
conf.setFailFast(false);
conf.setUriMappings(
Map.of(
"http://.../my-schema.json", "resource:META-INF/schemas/my-schema.json",
)
);
return JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7).getSchema(schemaStream, conf);
};
}
}
from("direct:testJson")
.to("json-validator:META-INF/schemas/my-schema.json?schemaLoader=#my-schema")
Related
I am using graph API JAVA sdk(v1.6.0) and I am trying to get all the groups that a specific user is in.
https://learn.microsoft.com/en-us/graph/api/user-getmembergroups?view=graph-rest-1.0&tabs=java#example
According to API doc, I could do something like below:
graphClient.me()
.getMemberGroups(securityEnabledOnly)
.buildRequest()
.post();
However, in java sdk 1.6.0, getMemberGroups() is not present under UserRequestBuilder.java class.
https://github.com/microsoftgraph/msgraph-sdk-java/blob/0041e58287f02036c37a8ae0a1bf30f1f616991a/src/main/java/com/microsoft/graph/requests/extensions/UserRequestBuilder.java.
Am i missing something?
I think they have replaced the getMemberOf() method with another one memberOf().
I was able to fetch all the groups for a particular user using the below code:
public static void getUserGroups(String accessToken) {
ensureGraphClient(accessToken);
String upn="test#testDomain.com";
IDirectoryObjectCollectionWithReferencesPage iDirectoryObjectCollectionWithReferencesPage = graphClient.users(upn).memberOf().buildRequest().get();
List<DirectoryObject> directoryObjects = iDirectoryObjectCollectionWithReferencesPage.getCurrentPage();
for (DirectoryObject directoryObject : directoryObjects) {
if(directoryObject.oDataType.equalsIgnoreCase("#microsoft.graph.group")) {
System.out.println(directoryObject.getRawObject().get("displayName"));
}
}
}
I create this date variable in client side:
this.latestDate = new Date(2001, 1, 1,1,1,1,1);
Here how it looks in client watch:
self.latestDate: Thu Feb 01 2001 01:01:01 GMT+0200 (Jerusalem Standard Time)
here is angularjs service that I use to asyncroniusly call my web api method:
$http.get(serviceUrl + "?date=" + self.latestDate);
And here is the web api method that I call from cilent:
[HttpGet]
public HttpResponseMessage GetByDate(DateTime date){}
But each time I call for web api method above, I get this error on cilent:
<Error>
<Message>The request is invalid.</Message>
<MessageDetail>
The parameters dictionary contains a null entry for parameter 'date' of non-nullable type 'System.DateTime' for method 'System.Net.Http.HttpResponseMessage GetByDate(System.DateTime)' in 'SensorObservation.Web.SensorsDataController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.
</MessageDetail>
</Error>
Any idea why I get the error above?
First, doing this is a really bad idea:
$http.get(serviceUrl + "?date=" + self.latestDate);
A URL is a structured text format; it has formatting rules that must be followed. When you dump unstructured text into a structured format by using simple string concatenation, you are likely to be breaking some of those rules. I would recommend using the jQuery param function for this.
Second, you are serializing the date to a string using the default format, which is the one you see in the client watch. This may or may not work on the server. A better bet is to serialize using a well known format such as ISO 8601. I would recommend using the JavaScript date toISOString function for this.
Applying these changes, your API call code would look something like this:
var query = jQuery.param({ date: self.latestDate.toISOString() });
$http.get(serviceUrl + "?" + query);
Update
I ran a quick test since I was in my WebAPI code already, and you can create and use an endpoint with a DateTime parameter as long as the URL is formatted correctly.
My test endpoint looks like this:
[HttpGet]
[Route("test/datetest")]
public HttpResponseMessage DateTest(DateTime d)
{
HttpResponseMessage response = new HttpResponseMessage();
response.Content = new StringContent(d.ToString(), Encoding.UTF8, "text/plain");
return response;
}
It echoes the date back as expected.
I don't understand how the below class is able to recognize the request /customers.json as the /customers path and able to extract and extract the json extension. There is no path parameters.
"Consider this
JAX-RS resource class:
#Path("/customers")
public class CustomerResource
{
#GET
#Produces("application/xml")
public Customer getXml() {...}
#GET
#Produces("application/json")
public Customer getJson() {...}
}
For this CustomerService JAX-RS resource class, if a request of GET /custom
ers.json came in, the JAX-RS implementation would extract the .json suffix and remove
it from the request path. It would then look in its media type mappings for a media
type that matched json. In this case, let’s say json mapped to application/json. It
would use this information instead of the Accept header and dispatch this request to
the getJson() method."
I got the official answer from author: "The specification does not define a facility for this, but most JAX-RS implementations support it."
Using Jackson 2.2.2 and Apache CXF web services client and server API.
I'm finding it impossible to serialize / deserialize JSON without failure.
Java class:
MyPojo
{
..... various properties
}
JSON produced from Jackson:
{
"MyPojo":
{
..... various properties
}
}
When I send the exact same JSON back to Jackson for it to consume, it fails with:
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException:
Unrecognized field "MyPojo" (class app.model.MyPojo), not marked as ignorable (17 known properties: ,.....
Ideally, Jackson would not wrap the MyPojo object with {"MyPojo":} because I only ever exchange MyPojo objects, so it is implied.
To that end, how can I get Jackson to produce:
{
..... various properties
}
Then, how do I get jackson to consume the same JSON without failing? i.e. what ObjectMapper configuration or annotations or combination of both do I have to use?
If this is impossible, then how do I configure / annotate to get Jackson to consume the "wrapped" JSON without failing?
ALSO,
I have the same issues when producing / consuming an array of MyPojo objects:
JSON produced from Jackson:
{
"MyPojo":
[
{
..... various properties
},
{
..... various properties
}
]
}
..when consumed fails with:
com.fasterxml.jackson.databind.JsonMappingException:
Can not deserialize instance of app.model.MyPojo[] out of START_OBJECT token
Again, ideally (but not essential) Jackson would produce / consume:
[
{
..... various properties
},
{
..... various properties
}
]
Note, the Apache CXF WS appears to perform some magic via its #GET, #POST, etc, annotations as when used in conjuntion with a RESTful WS resource method which returns a MyPojo object, i.e. it appears that after my method returns the object, it is transformed into JSON.
To that end, I am unsure if a local or even global ObjectMapper will influence the output, so this should also be considered when answering.
Another note, I also need the same POJO to be produced and consumed in XML via JAXB.
EDIT:
I am now quite certain that TomEE/CXF is not using Jackson and that this is the cause of my issues. I'll update when I get it to work.
RESOLVED:
Further investigation revealed that whilst the JSON was being deserailized by Jackson, the default Jettison provider was not being overriden with Jackson when serializing due to misconfiguration of default JSON provider in CXF/TomEE. This resulted in a Jackson - Jettison formatting mismatch.
On stackOverflow are more than many answered questions like yours.
This is a solution:
objectMapper.configure(SerializationConfig.Feature.WRAP_ROOT_VALUE, true);
You can see similar questions:
Use class name as root key for JSON Jackson serialization
Enable Jackson to not output the class name when serializing (using Spring MVC)
I am developing JAX-RS Rest service using Apache CXF. After deploying it to Tomcat 7 server, if I type the URL http://localhost:8080/Rest/rest?_wadl it shows me the WADL. but if I enter the URL http://localhost:8080/Rest/rest/retrieve it gives me 404 error.
In above URLs: Rest is the name of my project
/rest is the url-pattern for my CXFServlet which is specified in web.xml
/ is the address of jaxrs:server which is specified in beans.xml
retrieve is the path of service which is specified in my interface with #Path annotation.
(My apologies: I can't provide the XML documents referred to above.)
I think this is a CXF bug which get the incorrect base URL for restful web services.
The class "org.apache.cxf.transport.servlet.ServletController" invokes the method "getBaseURL" of the class "org.apache.cxf.transport.servlet.BaseUrlHelper".
It gets the base URL from request URL, and it ignores the parameters part.
This is correct for SOAP web servcies, because SOAP web services URL is just like: http://host:port/basepath?para=a. Unfortunately, for restful web services, the URL is just like http://host:port/basepath/method/parameter. The correct base URL should be http://host:port/basepath, but actually, the BaseUrlHelper gives you http://host:port/basepath/method/parameter. It just gives the URL before "?". It's why the result is correct when you access http://localhost:8080/Rest/rest?_wadl, in this case, it gives the correct base URL http://localhost:8080/Rest.
If you access http://localhost:8080/Rest/rest?_wadl at first then you access http://localhost:8080/Rest/rest/retrieve, it would be correct. Because, CXF set the base URL as the address of EndpointInfo only at the first time. It means, you MUST access the correct base URL at the first time! :(
The solution is: override the method "getBaseURL(HttpServletRequest request)" of "org.apache.cxf.transport.servlet.ServletController", let it return correct base URL.
For example, step1: extends the ServletController.
public class RestfulServletController extends ServletController {
private final String basePath;
public RestfulServletController(DestinationRegistry destinationRegistry, ServletConfig config,
HttpServlet serviceListGenerator, String basePath) {
super(destinationRegistry, config, serviceListGenerator);
this.basePath = basePath;
}
#Override
protected String getBaseURL(HttpServletRequest request) {
// Fixed the bug of BaseUrlHelper.getBaseURL(request) for restful service.
String reqPrefix = request.getRequestURL().toString();
int idx = reqPrefix.indexOf(basePath);
return reqPrefix.substring(0, idx + basePath.length());
}
}
step2: extends CXFNonSpringServlet and use the RestfulServletController in the subclass
public class RestfulCXFServlet extends CXFNonSpringServlet {
... ...
private ServletController createServletController(ServletConfig servletConfig) {
HttpServlet serviceListGeneratorServlet = new ServiceListGeneratorServlet(destinationRegistry, bus);
ServletController newController = new RestfulServletController(destinationRegistry, servletConfig,
serviceListGeneratorServlet, basePath);
return newController;
}
}
step3: instead of CXFNonSpringServlet , you use the derived class RestfulServletController.
Don't forget, you should config the "basePath" as /Rest/rest.
Hope this can help you.