Have following situation:
A class with a List field like:
#XMLType
#XMLAccessType(XMLAccessorType.FIELD)
#XMLRootElement(name = "container")
public class ListContainer {
#XMLElementWrapper(name="elements")
private List<Element> elements = new ArrayList<>();
....
}
The Element class is an abstract JAXB annotated class with #XMLRootElement annotation like:
#XMLType
#XMLRootElemenent
public abstract class Element {
....
}
These classes define some kind of Framework and users shall be able to add own implementations of Element class within own JAR packages. What I would like to achieve, is that after unmarshalling I would have in elements field of the instance of class ListContainer class instances which were introduced as extensions to the framework. For instance let say there is a class DummyElement in some other ext1.jar, which is in the class path, and it looks like following:
#XMLType
#XMLRootElement(name = "dummy")
public class DummyElement extends Element {
....
}
in ext2.jar I will have EasyElement like:
#XMLType
#XMLRootElement(name = "easy")
public class EasyElement extends Element {
...
}
in xml there on the place I would have something like:
<container>
<elements>
<dummy>....</dummy>
<easy>...</easy>
<easy>....</easy>
<dummy>...</dummy>
</elements>
</container>
expected result should be, that unmarshalled instance of ListContainer class will have 2 DummyElement instances and 2 EasyElement instances in elements fields.
So far if I leave ListContainer class annotated like this - I will have nothing in list. If I annotated with #XMLAnyElement(lax=true) then I will have ElementNSImpl instances.
Thank you for ideas in advance.
Update:
The solution is in control over creation of JAXBContext. I created service interface, which delivers me a list of classes required for context like:
public interface XMLContextProvider {
Set<Class> getJAXBContextClasses();
}
Then I created in framework a class which implements this interface and lists all classes I require from side of the framework. The same was done for extensions. The classes registered in META-INF/services - see ServiceLoader. Then I created a utility class, which utilises the ServiceLoader to find all providers and creates the JAXBContext with the list of all classes gathered from all providers. With this context it is possible to Marshal and Unmarshal. Additionally as I utilise JAX-RS I have created a Resolver for JAXBContext:
#Provider
public class XMLContextResolver implements ContextResolver<JAXBContext> {
private JAXBContext ctx;
public XMLContextResolver() {
ctx = <here goes call to utility class>
}
#Override
public JAXBContext getContext(Class<?> type) {
if (this.classes.contains(type)) {
return this.ctx;
}
return null;
}
}
Related
I have a Spring design problem that I've not come across before:
I have an application that manages a bunch of POJOs, I would like to register a factory for each of these POJO classes so a centralised #Component can do the management. Something like this:
class RouteLink implements Link {
}
class HiddenLink implements Link {
}
... lots of others
interface Loader {
Link load(Element xml);
}
#Component
class Manager {
private final Map<String, Loader> loaders = ...
public void create(Element xml) {
// Create link
final String type = ... // from XML
final Loader loader = loaders.get(type);
final Link link = loader.load(xml);
// Do something with the link we created
...
}
}
(The links are created from an XML element, but that's not important to the question - it could be from text, or other POJOs, etc).
Now I would like to co-locate the POJO and it's associated Loader. I could create a #Configuration class that creates a #Bean for each type but that violates the co-location and requires the developer (me!) to continually switch between source files.
Ideally I would like to do something like the following:
class RouteLink implements Link, Loader {
...
// <--- some Spring magic here to register this as a factory
public Link load(Element xml) {
...
}
}
The load() method cannot be a #Bean or a #Component because we are dealing with POJOs. So I'm forced to create a new class just to call a single method:
class RouteLink ... {
...
#Component
public class RouteLinkLoader implements Loader {
public Link load(Element xml) { .... }
}
}
and the loaders are registered with the manager like this:
public Manager(ApplicationContext ctx) {
loaders = ctx.getBeansOfType(Loader.class);
}
It works, sort of, but I can't help feeling I'm missing something. Is there any way of registering the load methods as components?
Notes:
I've tried denoting the POJO classes with #Configuration but that
then treats the class as a bean. But without that or another
stereotype annotation any #Bean in a POJO is not scanned.
I could just programatically register each POJO loader with the
manager but that seems a bit daft when using a DI framework.
The manager looks up the loader by name which is why we look them
up from the context rather than simply auto-wiring.
I've been developing with Spring for years but seem to have a blind-spot with this design (or lack of it!) Is there a better approach?
I'm not sure if I understand your problem correctly, what you want is to create objects that will be managed by Spring? Have you looked at Spring BeanFactory?
So it looks like there is no magic solution to this if we want to co-locate the factory and POJO code in the same source file, basically one has to create a separate #Component to register the POJO factories.
This means we have to wrap every factory method in a class such that it can be component scanned, rather than (for example) just having a static class constant to do it, something like this:
class PojoClass {
#MagicAnnotationHere
public static final Loader LOADER = xml -> new PojoClass(...);
}
Can't be done, so the factory method becomes a first-class component class which means a lot more code:
class PojoClass {
...
#Component
class PojoLoader implements Loader {
#Override
public void load(Element xml) { ... }
}
}
On the positive side the factories can be #AutoWired into the manager component as follows:
#Component
class Manager {
#Autowired
private final Map<String, Loader> loaders = new HashMap<>();
Spring auto-magically populates the map indexed by bean name, which is precisely what I needed to lookup the factory by name. I'll call that a score-draw!
Question:
In order to Inject all subclasses of a superclass with no common interface, I created an interface tightly-coupled to said superclass, that every "properly" written subclass is supposed to implement.
This works, but seems insane. Was there a better way?
A simple cast do not work, as the Instance holds only a proxy that do not resolves to any real subclass of the interface when called. This results in a ClassCastException.
Some context:
I was recently tasked to provide framework code for an application. In this application, several data transfer objects are mapping from and to service level POJOs, but their mappings are not always trivial. Dozer is used to do most of the work and to avoid boilerplate code.
In the specific cases requiring explicit mapping instructions, the current recommendation with Dozer is to use the API driven mapping. All the BeanMappingBuilder subclasses, defining the mappings, should be added to the Dozer mapper upon initialisation.
In order to keep all the work needed to add a new BeanMappingBuilder in one place, I came with a convoluted use of dependancy injection that will automatically add it to the Dozer mapper, despite it having no common interface, only a common superclass with the others.
Some code:
The interface:
#Local
public interface DtoBeanMappingBuilder {
BeanMappingBuilder get();
}
Subclass example:
#Stateless
public class SomeDtoMappingBuilder extends BeanMappingBuilder implements DtoBeanMappingBuilder {
#Override
public BeanMappingBuilder get() {
return this;
}
#Override
protected void configure() {
mapping(
// Some mapping...
);
}
}
Mapper with injection point:
#Singleton
#Startup
public class DtoBeanMapper {
private DozerBeanMapper innerMapper;
#Inject
#Any
private Instance<DtoBeanMappingBuilder> mappingBuilders;
public <D> D map(Object source, Class<D> destinationClass) {
return innerMapper.map(source, destinationClass);
}
#PostConstruct
private void init() {
innerMapper = new DozerBeanMapper();
mappingBuilders.forEach(mb -> innerMapper.addMapping(mb.get()));
}
}
I have a class annotated with #Component and #Service. The usual way of getting the instance of this class from the beans container is using #Reference:
#Reference private MyClass myclass;
How could I retrieve the instance using a string key as we do with ApplicationContext in Spring Web applications? I've tried with ComponentContext.locateService but I don't know if this is correct nor which key value I have to use.
MyClass myclass = (MyClass)context.locateService("????"); //Which is the way?
I edit my question, I'll try to explain better.
I have a class like this:
#Component
#Service
class MySvcImpl implements MySvc { ... }
injected this way:
class Main {
#Reference private MySvc svc;
void method1(){
svc.doXXX();
}
}
In this case I have a single class. I'd want to have a bunch of component subclasses (MySvcSubX) so that I can use any of them according to a parameter. Allegedly, I'd not need the #Reference line anymore.
#Component
#Service
class MySvcSub1Impl extends MySvcImpl implements MySvc { ...}
//The same with MySvcSub2Impl, 3, and so forth
And then in my Main class:
void method1(String key){
MySvc svc = callToLocateBeanById(key);
}
I should not need to add a reference for each of the subclasses to be able to locate them by their name.
Here you go:
ApplicationContext context = new ClassPathXmlApplicationContext(
"classpath*:mySpringConfig.xml");
MyClass myClassBean = (MyClass) context.getBean("myClass");
You can publish a #Component with a property :
#Component(property="type=xxx")
public class MyComponent implements MySvc {
}
and then query the osgi registry with a filter on this property :
BundleContext bc = ..;
Collection<ServiceReference<MySvc>> ref = bc.getServiceReferences(MySvc.class, "(type=xxx)")
// check cardinality, etc
MySvc svc = bc.getService(ref);
// use svc
bc.ungetService(ref);
If you know the key you are looking for at compile time (or though some configuration), you can inject a reference with a target :
#Reference(target = "(type=xxx)")
private MySvc component;
Old answer
You should use the name of the reference. This name can be specified in #Reference, but the default is generated from the name of the property, or the bind/unbind method (see the javadoc for this annotation)
In your example, it should be :
MyClass myclass = (MyClass)context.locateService("myClass");
If you're not sure, you can look at the generated xml from your component, you'll see the generated name.
I have a JAXB model generated from MOXy's version of XJC. The xjc:superclass tag was used in the binding's file so all the objects extend a common class.
package my.package
//Base.java
#XmlTransient
public class Base {
//...
}
//MyTag.java (generated from XJC)
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {/*...*/})
#XmlRootElement(name = "myTag")
public class MyTag extends Base {
//...
}
The model nor the schema can be changed, but I can change the Base class.
I need to extend MyTag, as well as some other classes in the model, so I can customize its method behaviors from the Base class. So I extended MyTag and the other domain classes that needed custom behavior, as well as the ObjectFactory. These classes exist in a separate Java package.
package my.extended.package
//MyTagExtended.java
public class MyTagExtended extends MyTag {
//...
}
//CustomObjectFactory.java
public class CustomObjectFactory extends ObjectFactory {
//...
#Override
public MyTagExtended createMyTag() {
return new MyTagExtended();
}
//...
}
Application code:
package application
//Application.java
System.setProperty("org.eclipse.persistence.moxy.annotation.xml-value-extension", "true");
JAXBContext jc = (JAXBContext) JAXBContext.newInstance(XPSObjectFactory.class);
JAXBUnmarshaller u = jc.createUnmarshaller();
return u.unmarshal(xmlFile);
The problem I'm having is MOXy seems to randomly decide whether to call the CustomObjectFactory's or ObjectFactory's methods.
In the CustomObjectFactory class, if I have only one overridden method, that method is always called. However, when I put in more, MOXy seems to randomly decide whether or not to call ObjectFactory's method's or CustomObjectFactory's.
When I use the same sort of setup with the Oracle's JAXB implementation that's supplied with the JDK, it works fine. The CustomObjectFactory's methods are always called.
Is there a configuration that needs to be set? How can I configure MOXy to always use my CustomObjectFactory's methods?
EDIT:
To clarify, here's how I made the same scenario work with Oracle's JAXB implementation:
JAXBContext jc = JAXBContext.newInstance("my.package");
Unmarshaller u = jc.createUnmarshaller();
u.setProperty("com.sun.xml.internal.bind.ObjectFactory", new CustomObjectFactory());
I tried to set the ObjectFactory property on the MOXy unmarshaller, but it threw an exception.
I found a workaround for MOXy. I found some information on XmlClassExtractor, which can be used to specify which class to instantiate. Since I can't modify the domain objects, an XML file was used instead.
I kept the extended classes the same, but modified Application.java and wrote a binding.xml file and a ClassExtractor:
package application
//Application.java
System.setProperty("org.eclipse.persistence.moxy.annotation.xml-value-extension", "true");
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, "classExtractor.xml");
JAXBContext jc = (JAXBContext) JAXBContextFactory.createContext(new Class[]{CustomObjectFactory.class}, properties);
JAXBUnmarshaller u = jc.createUnmarshaller();
return u.unmarshal(xmlFile);
classExtractor.xml:
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="my.package"
version="2.3">
<java-types>
<java-type name="MyTag">
<xml-class-extractor class="my.extended.package.MyTagClassExtractor"/>
</java-type>
</java-types>
</xml-bindings>
Class extractor:
package my.extended.package
//MyTagExtractor.java
public class MyTagExtractor extends ClassExtractor {
#Override
public Class<? extends Base> extractClassFromRow(Record databaseRow, Session session) {
return MyTagExtended.class;
}
}
This seems to work, but it's quirky and prone to programmer errors since multiple source files have to be edited to get the desired functionality. Oracle's ObjectFactory property on the unmarshaller was very easy and streamlined. Does anyone have a better answer?
I've read a lot about getting generic type at runtime and I've understood that to prevent full type erasure and get generic type without giving it to constructor I can use an anonymous class plus an utility method, i.e.
interface Generic<T> {
public Class<T> getGenericType();
}
#Component
class GenericImpl<T> extends AbstractGenericImpl<T> {
}
abstract class AbstractGenericImpl<T> implements Generic<T> {
protected Class<T> klass;
#SuppressWarnings("unchecked")
public Class<T> getGenericType() {
if (klass == null) {
// this is a spring utility method
klass = (Class<T>) GenericTypeResolver.resolveTypeArgument(getClass(), AbstractGenericImpl.class);
}
return klass;
}
}
Now using the previous class hierarchy I can have a working getGenericType method if and only if I instantiate a Generic<Anything> using an anonymous class. In fact in this test only the first two assertions are working:
#Test
public void testGeneric() throws Exception {
Generic<String> anonymous = new AbstractGenericImpl<String>() {};
Generic<String> anonymous2 = new GenericImpl<String>() {};
Generic<String> concrete = new GenericImpl<String>();
// assertion
assertThat("Anonymous of abstract class", anonymous.getGenericType(), equalTo(String.class));
assertThat("Anonymous of concrete subclass", anonymous2.getGenericType(), equalTo(String.class));
assertThat("With non anonymous class it fails", concrete.getGenericType(), equalTo(String.class));
}
The third one is failing with Expected: <class java.lang.String> but: was <class java.lang.Object>
Now I'd like to use the Generic class with spring #Autowired annotation i.e.
#Autowired Generic<String> auto;
#Test
public void testAutowiring() {
assertThat(auto, instanceOf(Generic.class));
assertThat(auto.getGenericType(), equalTo(String.class));
}
but the second assertion fails with the same error as above (Object instead of String), because spring container internally instantiate it with new GenericImpl<String>()
I've already tried to make constructor of GenericImpl<T> protected and also to declare GenericImpl<String> itself abstract but in both cases spring fail with a Cannot instantiate bean exception.
Is there any simple way to tell spring to instantiate classes using anonymous classes?
Additional details
The final class will convert a json stream into a POJO with Jackson and the Jackson library needs the Class<T> field to unmarshal objects.
// here I convert json stream to a POJO and I need the generic type
mapper.readValue(hit.source(), getGenericType());
Since I have multiple POJO classes to convert from to JSON I've implemented all the logic in a common class with generics called Retriever. At the end I'll have one Retriever for each POJO and often those retrievers are autowired in other classes.
#Autowired Retriever<Artifact> retriever;
Currently I've a constructor in Retriever which takes a Class<T> parameter and use it later to perform conversion. In the spring context I've this for autowiring
<!-- Since retriever has a Class<T> constructor this is the only way I found to resolve its dependency -->
<bean id="artifactRetriever" class="a.b.c.RetrieverImpl">
<constructor-arg value="a.b.c.Artifact"/>
</bean>
and I need one of this for each POJO for which I need conversion. This approach works but it's a little verbose and it clutters the application context with useless lines. So I was looking for a way to get rid of all this noise in application context.
It's not possible to create and instantiate anonymous classes in-place with Spring, not with XML configuration (since it needs class name, and you don't have one).
Ok, final solution for my use case will use the approach described in this answer. It would be better because it will be possible to track usages and I'll get rid of every problem I'm having with the current approach.
In that way I can do the following
#Component
public class ArtifactImpl extends AbstractGenericImpl<Artifact> {
}
#Component
public class MaterialImpl extends AbstractGenericImpl<Material> {
}
#Component
class Usage {
#Autowired ArtifactImpl foo;
#Autowired MaterialImpl bar;
}
In this way everything is checked at compile time and I got rid of Class<T> constructor in fact I have autowiring in place (without #Qualifier) and the following test is working:
#RunWith(SpringJUnit4ClassRunner.class)
public class AutowiringTest {
#Autowired Usage test;
public void testAutowiring() {
assertThat(test.foo.getGenericType(), equalTo(Artifact.class));
assertThat(test.bar.getGenericType(), equalTo(Material.class));
}
}
Original answer
Ok, I've found out that what I'm asking will be useless because autowiring happens at runtime and so having two autowired object with different objects will lead to spring errors, i.e. this won't work:
#Configuration
class RetrieverProvider {
#Bean
Retriever<Artifact> getArtifact() {
return new RetrieverImpl<Artifact>() {};
}
#Bean
Retriever<Material> getMaterial() {
return new RetrieverImpl<Material>() {};
}
}
class InjectedAttempt {
// at injection time, i.e. runtime, type erasure prevent spring to distinguish
#Autowired Retriever<Artifact> foo; // this type
#Autowired Retriever<Material> bar; // from this type
// so it cannot perform injection by type
}
The only way to get that working is to use qualifiers in this way, but I don't like this approach, so I'll remain with xml configuration and constructor arguments.
#Configuration
class RetrieverProvider {
#Bean #Qualifier("artifact") Retriever<Artifact> getArtifact() {
return new RetrieverImpl<Artifact>() {};
}
#Bean #Qualifier("material")
Retriever<Material> getMaterial() {
return new RetrieverImpl<Material>() {};
}
}
class Injected {
#Autowired #Qualifier("artifact") Retriever<Artifact> foo;
#Autowired #Qualifier("material") Retriever<Material> bar;
}
As a side note guice has support for generic injections, maybe spring has something similar.