Creating mixins with CGLIB that implement a new interface - java

First off, I don't think this is necessarily a good idea, I'm just seeing if this is really possible. I could see some benefits, such as not having to explicitly convert to objects that we're sending to the client and using an interface to blacklist certain fields that are security concerns. I'm definitely not stuck on the idea, but I'd like to give it a try.
We're using Spring MVC + Jackson to generate JSON directly from objects. We have our domain object that contains necessary data to send to the client and we have a list of error strings that are added to every outgoing JSON request as needed.
So the return JSON might be something like
{ name: 'woohoo', location : 'wahoo', errors : ['foo'] }
Currently, we have a class that models what should be on the client side, but we always extend a common base class with the error methods.
So, we have:
interface NameAndLoc {
String getName();
String getLocation();
}
and
interface ResponseErrors {
List<String> getErrors();
void appendError(String);
}
We have two classes that implement these interfaces and would like to have CGLIB generate a new class the implements:
interface NameAndLocResponse extends NameAndLoc, ResponseErrors {}
Presently, with CGLIB mixins, I can generate an object with the following:
Object mish = Mixin.create(
new Class [] {NameAndLoc.class, ResponseErrors.class},
new Object [] { new NameAndLocImpl(), new ResponseErrorsImpl() } );
I could then cast the object to either NameAndLoc or ResponseErrors, however, what I would like to do is create an object that uses the same backing classes, but implements the NameAndLocResponse interface, without having to extend our common error handling class and then implement NameAndLoc.
If I attempt to cast with what I have, it errors out. I'm sure this is possible.
I think it is very similar to this, but not quite: http://www.jroller.com/melix/entry/alternative_to_delegate_pattern_with

Simply add the NameAndLocResponse interface to the Class array in the Mixin constructor as the last argument. The resulting object will implement it. You can find an example of this in this blog entry: http://mydailyjava.blogspot.no/2013/11/cglib-missing-manual.html

Related

JAXB "nor any of its super class is known to this context" avoid #XmlSeeAlso

Explanation & Workaround
Currently I am using JAX-RS and letting JAXB bindings automatically handle converting the data to XML and JSON for me in a JEE6 project. Everything is working absolutely fantastically until I try to create a generic response object to wrap all of my information in.
When I attempt to use my generic response class com.eln00b.Wrapper (which contains a private Object result attribute within it) I get:
javax.xml.bind.MarshalException - with linked exception: [com.sun.istack.SAXException2: class com.eln00b.CustomObject nor any of its super class is known to this context. javax.xml.bind.JAXBException: class com.eln00b.CustomObject nor any of its super class is known to this context.]
So I add to com.eln00b.Wrapper:
#XmlSeeAlso ({com.eln00b.CustomObject})
public class Wrapper {
}
Everything works fine.
The Problem
I want this to be extremely generic. I do not want t constantly add classes to the #XmlSeeAlso annotation on the com.eln00b.Wrapper class. How do I have the system automatically locate all of my classes for the JAXB context?
Even if it's a hack where I use something like Reflections to load the data, that's fine. I'm just not sure how to get the context to load all of that data without the #XmlSeeAlso annotation. With the large amount of annotations I will be creating it will just simply not work.
How It Worked Manually
It worked manually just by adding the data like so doing manual conversions. However, I do not want to use manual XML/JSON creation unless I absolutely need to (I don't want to deal with content negotiation or anything like that).
Sample:
JAXBContext.newInstance(new Class[] {Wrapper.class, CustomObject.class});
So here is what the essence of the custom resolver looks like:
#Provider
#Produces ({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public class JaxbContextResolver implements ContextResolver<JAXBContext> {
#Override
public JAXBContext getContext(Class<?> type) {
// load appropriate context data
Class[] bindTypes = ...
// create
try {
return JAXBContext.newInstance(bindTypes);
} catch (JAXBException e) {
// todo: this can be handled better but works for the example
throw new RuntimeException(e);
}
}
}
Now, the processing for "load appropriate context data" is pretty simple. By basically mimicking #XmlSeeAlso using runtime data:
Create a custom something (annotation, processing method, whatever) that marks a particular field/method as "contextual"
Load the field/method data pulling the data types out
Make sure you do not load duplicates and check for infinite recursion possibilities
Now, I used some caching to help make things more efficient for myself. I also created a slightly more complex setup for my root object where it actually kept track of the class data on its own and made it pretty speedy. I also created an alternative that marked classes as "contextual" that I used package inspection to load via annotations and just automatically add to the context but I have not checked efficiency on that yet. I have some ideas for a 3rd implementation, but I want to get more benchmarking completed.

Retrieving an instance using a string literal with Google Guice

I have multiple modules with service interfaces binding to their corresponding types and I am able to get an instance by using
injector.getInstance(MyServiceInterface.class)
I would like to retrieve the instance using
injector.getInstance("MyServiceInterface")
i.e. a string literal instead of the class type
How can I achieve this ?
To elaborate my question further - I can retrieve the Class object from the string literal using a Class.forName(literal) call and then use it to retrieve the instance with a injector.getInstance(clsInstance) .
After retrieving the instance which I receive in my base service type interface I need to use reflection to invoke the method of the service object.
so Service serv = injector.getInstance(MyCustomService.class)
Now I need to invoke myCustomMethod() present in MyCustomService through reflection since this invoker is generic and is intended to work with multiple services without being aware of their actual type.
I will also need the Method interceptors configured on the service interfaces to be invoked transparently when I invoke the method on this instance reflectively.
While I'm not certain if there's functionality for that built into Guice itself, you could try getting the relevant Class<?> object yourself.
Something along the lines of:
Class<?> myServiceInterfaceClass = Class.forName("path.to.MyServiceInterface");
injector.getInstance(myServiceInterfaceClass);
This does however require that the current Classloader can access that specific class, etc.
This can't be done within Guice... because it can't be done, period! Think about it, let's say you have two of the same class name in different packages. Which class would you instantiate?
So at the very least the String would have to have the fully qualified class name, e.g. instead of Integer, it would have java.lang.Integer.
However, if you know which classes you want to support in advance, you can use a MapBinder.
Tweaking their example to match your use case:
public class ServiceModule extends AbstractModule {
protected void configure() {
MapBinder<String, MyServiceInterface> mapbinder
= MapBinder.newMapBinder(binder(), String.class, MyServiceInterface.class);
mapbinder.addBinding("MyServiceInterface").to(MyServiceImpl.class);
bind(MyServiceInterface.class).to(MyServiceImpl.class);
}
}
Now you can inject like this:
class ServiceManager {
#Inject
public ServiceManager(Map<String, MyServiceInterface> services) {
MyServiceInterface service = stacks.get("MyServiceInterface");
// etc.
}
}
Please note when you call inj.getInstance() you do have to know the return type of the Object you're trying to create, unless you are planning on doing:
Object foo = inj.getInstance(myString);

Java Inheritance and Wrapping

I have a generated object that I want to:
Preserve existing functionality of without injecting into the constructor and rewriting every method to call injectedObject.sameMethod().
Add additional functionality to that generated object without modifying the generated object.
add additional functionality to.
For example:
public class GeneratedObject {
public String getThis() { ... }
public String getThat() { ... }
}
public interface ObjectWrapper {
String doThisWithThat();
}
public class ObjectWrapperImpl extends GeneratedObject implements ObjectWrapper {
String doThisWithThat() { ... }
}
However, downcasting is not allowed, what is the proper implementation without rewriting a bunch of redundant code just to wrap the object?
I think decorator pattern may help you: "The decorator pattern can be used to extend (decorate) the functionality of a certain object at run-time, independently of other instances of the same class"
Have you tried aspectj? http://www.eclipse.org/aspectj/doc/next/progguide/semantics-declare.html It's a bit complicated but so is your request.
If you can extract an interface from GeneratedObject, then it would be possible to do this using a dynamic proxy. You would make a proxy which implemented the extracted interface and ObjectWrapper, with an invocation handler which passed all calls to methods in the GeneratedObject interface through to the delegate, and sent the doThisWithThat() calls elsewhere.
Proxies aren't pretty, but the ugliness is at least well-localised.

Generics and JSON

I am using the Play framework.
I want to use the function renderJSON with 2 Objects as an argument. It doesn't seem to be possible so I am trying to create a class that contains the 2 objects. In order not to have to create a new class everytime, I want to use Generics but it doesn't seem to work:
Model :
public class JSONContainer<T> extends Model {
private T myT;
private StatusMessage mySm;
public JSONContainer(T myT, StatusMessage mySm) {
this.myT = myT;
this.mySm = mySm;
}
}
and then :
In a function of a Controller:
JSONContainer<User> myJ = new JSONContainer(logged,sm);
renderJSON(myJ);
where logged is a User, sm is a StatusMessage. I get the error:
type: 'play.exceptions.JavaExecutionException'
If I don't use Generics, it works fine. Any idea?
The console gives this output, where the line 43 is:
JSONContainer<User> myJ = new JSONContainer(logged,sm);
Generic entities can't be mapped by Hibernate.
You should do the generic class abstract and create specific implementations (using User and any other possible values of T). This should solve the issue
Instead of using a JSONContainer like I did, I think the best way is to go with Collection as shown in this user guide for GSON made by Google (the JSON mapper used by Play apparently) at http://sites.google.com/site/gson/gson-user-guide#TOC-Collections-Examples:
Collection collection = new ArrayList();
collection.add(logged);
collection.add(sm);
renderJSON(collection);
Collection are good for serializing (Java object to JSON) but not good for deserializing (see the GSON user guide for more insight).
It is better, IMHO, to use Collection than JSONContainer as JSONContainer are not useful in that case and don't give more possibilities.

Jackson JSON library: how to instantiate a class that contains abstract fields

I want to convert a JSON string into java object, but the class of this object contains abstract fields, which Jackson can't instantiate, and doesn't produce the object. What is the easiest way to tell it about some default implementation of an abstract class, like
setDefault(AbstractAnimal.class, Cat.class);
or to decide about the implementation class based on JSON attribute name, eg. for JSON object:
{
...
cat: {...}
...
}
i would just wite:
setImpl("cat", Cat.class);
I know it's possible in Jackson to embed class information inside JSON, but I don't want to complicate the JSON format I use. I want to decide what class to use just by setting default implementation class, or by the attribute name ('cat') - like in XStream library, where you write:
xStream.alias("cat", Cat.class);
Is there a way to do so, especially in one line, or does it require some more code?
There are multiple ways; before version 1.8, simplest way is probably to do:
#JsonDeserialize(as=Cat.class)
public abstract class AbstractAnimal { ... }
as to deciding based on attribute, that is best done using #JsonTypeInfo, which does automatic embeddeding (when writing) and use of type information.
There are multiple kinds of type info (class name, logical type name), as well as inclusion mechanisms (as-included-property, as-wrapper-array, as-wrapper-object). This page: https://github.com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization explains some of the concepts.
A full fledged answer with a very clear example can be found here: https://stackoverflow.com/a/30386694/584947
Jackson refers to this as Polymorphic Deserialization.
It definitely helped me with my issue. I had an abstract class that I was saving in a database and needed to unmarshal it to a concrete instance of a class (understandably).
It will show you how to properly annotate the parent abstract class and how to teach jackson how to pick among the available sub-class candidates at run-time when unmarshaling.
If you want to pollute neither your JSON with extra fields nor your classes with annotation, you can write a very simple module and deserializer that uses the default subclass you want. It is more than one line due to some boilerplate code, but it is still relatively simple.
class AnimalDeserializer extends StdDeserializer<Animal> {
public AnimalDeserializer() {
super(Animal.class);
}
public Animal deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException {
return jsonParser.readValueAs(Cat.class);
}
}
class AnimalModule extends SimpleModule {
{
addDeserializer(Animal.class, new AnimalDeserializer());
}
}
Then register this module for the ObjectMapper and that's it (Zoo is the container class that has an Animal field).
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new AnimalModule());
return objectMapper.readValue(json, Zoo.class);
The problem can be solved with the annotation #JsonDeserialize on the abstract class.
Refers to Jackson Exceptions Problems and Solutions for more info

Categories

Resources