I need to marshal a list of entities using jax-b in a jax-rs client, without creating a wrapper class for each entity needed (there are manny entities!). I notice the service is able to marshal a list of customers like this:
<customers>
<customer>.....</customer>
<customer>.....</customer>
</customers>
Which I on the client side is able to unmarshal by finding all customer nodes and adding them to a list manually. (I guess there's a better way to do this?)
Now, the real problem here is when I want to send a list of an entity(eg. customers) to the service. I want to marshal this list into an xml string before writing this string as the payload of the request to the service. This does not work since java.util.List or its descendants is not known to the marshaller.
javax.xml.bind.Marshaller.marshal(list, StringWriter);
javax.xml.bind.Unmarshaller.unmarshal(org.w3c.dom.node)
Any help is much appreciated!
Thanks!
-Runar
Edit:
Here's a snippet from the customer class:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Customer implements Serializable {
private String name;
.....
}
I'm trying to write a lightweight client using no 3rd party libraries not part of the standard implementation. Because of this I have written my own httpclient taking in payload objects, marhalling them and passing them to the payload of the request. When the response is received I read the xml and send it to unmarshalling. It would be awsome if I could do the marshalling/unmarshalling directly to/from string just as my jax-rs service does.
Ok, so I found no good solution to this. But since it seems the pattern for my jax-rs service is to generate a root node called <class name " + "s>, I did this to be able to send lists of objects to the service:
if (obj instanceof List) {
List list = (List) obj;
if (!list.isEmpty()) {
// Since the jax-b marshaller does not allow to send lists directly,
// we must attempt to create the xml as the jax-rs service would expect them,
// wrapped with the classname pluss an s.
String wrapper = list.get(0).getClass().getSimpleName() + "s";
// Make first letter in class-name lower-case
wrapper = Character.toLowerCase(wrapper.charAt(0)) +
(wrapper.length() > 1 ? wrapper.substring(1) : "");
marshaller.setProperty(javax.xml.bind.Marshaller.JAXB_FRAGMENT, true);
writer.write("<" + wrapper + ">");
for (Object o : (List) obj) {
marshaller.marshal(o, writer);
}
writer.write("</" + wrapper + ">");
}
} else {
marshaller.marshal(obj, writer);
}
Related
I am using Spring Integration to consume RSS feeds. Once I get a feed item, I need to enhance the data by using a field from the payload, call a Java class to get some additional data and store this with the payload before writing all the data to the DB.
What is the best way to do this, a payload enricher or a service activator and how to specify this using DSL?
Finally as the payload is an SyndEntry object, do I need to create a new payload with new fields?
Any pointers would be helpful.
Yes, you need a new payload type; you can use a simple POJO...
#Bean
public Enricher enricher() {
return new Enricher();
}
public static class Enricher {
public Enhanced enhance(SyndEntry entry) {
return new Enhanced(entry, "foo", "bar");
}
}
Then, in the DSL...
...
.handle("enricher", "enhance")
...
I am specifically using breezejs and the server code for breeze js converts the dbcontext into a form which is useable on the clientside using EdmxWriter.WriteEdmx. There are many properties which I have added JsonIgnore attributes to so that they don't get passed to the client side. However, the metadata that is generated (and passed to the clientside) from EdmxWriter.WriteEdmx still has those properties. Is there any additional attribute that I can add to those properties that I want ignored so that they are ignored by EdmxWriter.WriteEdmx? Or, would I need to make a separate method so as not to have any other unintended side effects.
You can sub-class your DbContext with a more restrictive variant that you use solely for metadata generation. You can continue to use your base context for persistence purposes.
The DocCode sample illustrates this technique with its NorthwindMetadataContext which hides the UserSessionId property from the metadata.
It's just a few extra lines of code that do the trick.
public class NorthwindMetadataContext : NorthwindContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Hide from clients
modelBuilder.Entity<Customer>().Ignore(t => t.CustomerID_OLD);
// Ignore UserSessionId in metadata (but keep it in base DbContext)
modelBuilder.Entity<Customer>().Ignore(t => t.UserSessionId);
modelBuilder.Entity<Employee>().Ignore(t => t.UserSessionId);
modelBuilder.Entity<Order>().Ignore(t => t.UserSessionId);
// ... more of the same ...
}
}
The Web API controller delegates to the NorthwindRepository where you'll see that the Metadata property gets metadata from the NorthwindMetadataContext while the other repository members reference an EFContextProvider for the full NorthwindContext.
public class NorthwindRepository
{
public NorthwindRepository()
{
_contextProvider = new EFContextProvider<NorthwindContext>();
}
public string Metadata
{
get
{
// Returns metadata from a dedicated DbContext that is different from
// the DbContext used for other operations
// See NorthwindMetadataContext for more about the scenario behind this.
var metaContextProvider = new EFContextProvider<NorthwindMetadataContext>();
return metaContextProvider.Metadata();
}
}
public SaveResult SaveChanges(JObject saveBundle)
{
PrepareSaveGuard();
return _contextProvider.SaveChanges(saveBundle);
}
public IQueryable<Category> Categories {
get { return Context.Categories; }
}
// ... more members ...
}
Pretty clever, eh?
Just remember that the UserSessionId is still on the server-side class model and could be set by a rogue client's saveChanges requests. DocCode guards against that risk in its SaveChanges validation processing.
You can sub-class your DbContext with a more restrictive variant that you use solely for metadata generation. You can continue to use your base context for persistence purposes.
The DocCode sample illustrates this technique with its NorthwindMetadataContext which hides the UserSessionId property from the metadata.
It's just a few extra lines of code that do the trick.
The Web API controller delegates to the NorthwindRepository where you'll see that the Metadata property gets metadata from the NorthwindMetadataContext while the other repository members reference an EFContextProvider for the full NorthwindContext.
Pretty clever, eh?
If you use the [NotMapped] attribute on a property, then it should be ignored by the EDMX process.
I am not sure if ServiceStack has a mechanism to prevent "JavaScript/HTML Injection" on Entities (Request Entities) properties.
Also as per my understanding entity's properties of type string is prone to JavaScript/HTML injection
If there is no in built mechanism please suggest me a better option.
One of the option which i see is use to validate may be using Fluent Validation or any other validating library
Use validation:
Yes you should be using Fluent Validation or another validation mechanism to sanitise all the values that are passed as a request to your ServiceStack service.
Why ServiceStack shouldn't sanitise for you:
ServiceStack won't do this for you, after all sending HTML and/or JavaScript in a request to the service may be perfectly legitimate, (i.e. where your service is a content manager for a blog), and it's wrong to assume the request is an injection attack.
ServiceStack isn't constricted to only being consumed by web applications, so it's up to the service to decide which values are appropriate.
It should be noted that ServiceStack does prevent SQL injection by escaping all parameters.
Encode HTML entities:
If you are concerned about HTML injection, then you should consider encoding HTML entities, then any unsafe values that are returned won't affect your result. You can do this easily using this request filter, and marking up your DTO with an attribute [EncodeHtml].
GlobalRequestFilters.Add((req,res,dto) => {
var dtoType = dto.GetType();
var filteredProperties = dtoType.GetPublicProperties().Where(p => p.PropertyType == typeof(string) && p.HasAttribute<EncodeHtmlAttribute>() && p.CanWrite);
foreach(var property in filteredProperties)
property.SetValue(dto, HttpUtility.HtmlEncode(property.GetValue(dto, null)), null);
});
On your DTO add the [EncodeHtml] attribute to the properties you want to protect.
[Route("/test", "GET")]
public class Test
{
public string UnsafeMessage { get; set; }
[EncodeHtml]
public string SafeMessage { get; set; }
}
The attribute declaration is simply:
public class EncodeHtmlAttribute : Attribute {}
Then when you send a request such as:
/test?unsafeMessage=<b>I am evil</b>&safeMessage=<b>I am good</b>
The result will be
UnsafeMessage: "<b>I am evil</b>"
SafeMessage: "<b>I am good</b>"
I hope this helps.
As per your suggestion if you want to throw an exception on any DTOs that may contain HTML then you could use a more general check which prevents any HTML in any strings on the DTO by checking against a regular expression, but I'd do this sparingly.
GlobalRequestFilters.Add((req,res,dto) => {
var dtoType = dto.GetType();
if(!dtoType.HasAttribute<PreventHtmlAttribute>())
return;
var filteredProperties = dtoType.GetPublicProperties().Where(p => p.PropertyType == typeof(string));
foreach(var property in filteredProperties){
var value = property.GetValue(dto, null) as string;
if(value != null && Regex.Match(value, #"<[^>]*>", RegexOptions.IgnoreCase).Success)
throw new HttpError(System.Net.HttpStatusCode.BadRequest, "400", "HTML is not permitted in the request");
}
});
Then use this attribute:
public class PreventHtmlAttribute : Attribute {}
On the DTO:
[PreventHtml]
[Route("/test", "GET")]
public class Test
{
...
}
For example, if I have standard request and response DTOs, linked up via IReturn<T>, what are the reasons to have a service method signature like the following, as seen in various online examples (such as this one, although not consistently throughout):
public object Get(DTO.MyRequest request)
rather than:
public IList<DTO.MyResponse> Get(DTO.MyRequest request)
Is an object return type here simply to support service features like gzip compression of the output stream, which results in the output being a byte array? It seems that one would want to have the appropriate stronger return type from these so-called "action" calls, unless I'm missing some common scenario or use case.
It used to be a limitation that the New API only supported an object return type, but that hasn't been the case for a while where all examples on the New API wiki page now use strong-typed responses.
One of the reasons where you might want to return an object return type is if you want to decorate the response inside a HttpResult, e.g:
public object Post(Movie movie)
{
var isNew = movie.Id == null;
Db.Save(movie); //Inserts or Updates
var movie = new MovieResponse {
Movie = Db.Id<Movie>(newMovieId),
};
if (!isNew) return movie;
//Decorate the response if it was created
return new HttpResult(movie) {
StatusCode = HttpStatusCode.Created,
Headers = {
{ HttpHeaders.Location, Request.AbsoluteUri.CombineWith(movieId) }
}
};
}
It's also useful if you want to return different responses based on the request (though it's not something I recommend), e.g:
public object Get(FindMovies request)
{
if (request.Id != null)
return Db.Id<Movie>(movie.Id);
return Db.Select<Movie>();
}
If you do choose to return an object I highly recommend decorating your Request DTO with the IReturn<T> marker to give a hint to ServiceStack what the expected response of the service should be.
I am using a sping ws endpoint with jaxb marshalling/unmarshalling to proudce a list of Organisation objects (our local type). The endpoint is SOAP 1.1, no parameters supplied on the request message.
I understand JAXB doesn't handle lists very well, so I use a wrapper class.
#XmlRootElement(name="orgResponse", namespace=....)
public class OrganisationListWrapper {
private ArrayList<Organisation> organisationList;
public getOrganisationList() {
return organisationList;
}
public setOrganisationList(ArrayList<Organisation> organisationList) {
this.organisationList = organisationList;
}
}
The endpoint....
#PayloadRoot(localPart=.... namespace=....)
#ResponsePayload
public OrganisationListWrapper getOrganisations() {
OrganisationListWrapper wrapper = new OrganisationListWrapper();
wrapper.setOrganisationList(.... call service layer get list ....);
return wrapper;
}
This works fine and I get a SOAP payload with
<orgResponse>
<organisationList>
... contents of organisation 1
</organisationList>
<organisationList>
... comtents of organisation 2
</organisationList>
.... etc ....
</orgResponse>
The Organisation class is not JAXB annotated. It is part of a large list of pre-existing classes that are being exposed through web services for the first time. Trying to get by without going in and annotating them all by hand.
I was able to override the name OrganisationWrapper with orgResponse in the XmlRootElement annotation. I would like to override the organisationList name in the child element with organisation but haven't been able to find an annotation that does this.
I can replace the array list name with organisation and it will work fine, but our coding standard here required us to put List on the end of our list names. I would like to try and stick to that. I have tried XmlElement, but that produced a jaxb exception.
Any suggestions would be appreciated.
Because JAXB default the access type to PUBLIC_MEMBER, make sure you annotate the property (getter) and not the field:
#XmlElement(name="organisation")
public getOrganisationList() {
return organisationList;
}
If you want to annotate the field then add the following annotation to your class:
#XmlAccessorType(XmlAccessType.FIELD)