How to map a Resource to an enum constant? - java

I'm currently refactoring a (former) monster of a method in a Spring-MVC controller. The method basically does the following things:
Digs up a few identifiers from the request
Gets an XML representation for a product identified by them from a cache
Uses an XSL stylesheet to produce a PDF (which it then stores to a cache and adds the key it can be found with to the Model).
I've been able to remove almost all duplicated logic by making a Product enum which contains all the other product specific things, but the locations of the XSL stylesheets are problematic. Previously they were configured as org.springframework.core.io.Resource-type properties of the controller bean, but now that the product specific things are in the enum, I would either need to map them somehow to the enum constants or find another solution for locating them.
I think it would be best to have the XSL as part of the enum since there's a 1-to-1 relationship between them, but there's no way to inject the resource there. Using the class loader to load the resource to the enum manually would work in tests, but would be problematic in production environment since the stylesheet files are not in the classpath there. Plus I wouldn't like to make the enum depend on any Spring stuff.
Any ideas on how to tackle this problem without making the enum and the controller too tightly coupled?

In the end I made the enum an inner class of the controller and added an abstract method called getXsl to it. The implementing enum constants now return the related Resource directly. I didn't have to change anything else since the Resource beans were already static.

Related

Is it possible to implement/override an abstract method with reflection?

I have a question about Reflection, but the motivation is from using Spring Framework.
Consider this project, which is a sort of Minimum Working Example version of a deployed project.
In the ProjectionResourceProcessorConfig class, I have an entityProjectionResourceProcessor method for every projection, and every entity in the database have a few projections. That's about 60 methods.
I don't want to keep this up because of the obvious maintenance disadvantage. I want to use Reflection in order to automatically register one bean for every projection class.
The postProcessBeanDefinitionRegistry method in the ProjectionResourceProcessorConfig class shows that I can get the list of classes I want to use to register one bean for each and shows how to register a bean programatically.
However, because I need to use the ProjectionResourceProcessor class, I need to override the getEntityClass method. I haven't been able to find a way to do that programatically. That's why I've declared the inner class. It shows the programatic bean registration working, but it falls in the same issue as requiring a piece of code for every bean.
Apart from reflection, I tried to use the setMethodOverrides method of the RootBeanDefinition class to override that method, but I couldn't manage to understand how to use that method. Google couldn't find any documentation or usage example (except for a vaguely related Chinese post with copies on several different websites).
I also tried to use the MethodReplacer class but I haven't found how to use it with annotation driven configuration.
I also tried to replace the getEntityClass method by a variable and replace the variable's value by reflection, but apparently when the variable is read the value that was set in the super class is the one that is retrieved.
To test the project, run the tests at DemoApplicationTests. It will print the projection of some entities. If they have links, it's working.
Is it possible to do what I want? If it is, how?
Thanks in advance.

How to implement an xml saveable/loadable class?

I would like to create a class, which would be loadable and saveable to an XML file. I want to use one class which is doing the loading task and I want to integrate it with the actual class that I want to save and load, everything seems to be doable up to the point where JAVA doesn't allow the class instance to be change from within the class, i.e. there is no:
this = JAXBLoader.load();
So currently that's the problem I'm facing.
And I want to be able to control the loading and saving it via the public methods from the class itself, so that from the outside I don't need any factories or managers to load it. Currently the only solution I've seen to this was if I extended the class that I want to save as an xml and then delegate all the methods to the intance of the actual class and then when loading a new instance from the file, the instance would get replaced. But it is a bit of overhead to have to delegate all of the methods, especially pain in the ass if you need to add new methods to the class and have multiple implementations...
So are there any good practices or patterns on achieving something similar or solving the problem I demonstrated above? Actually I'm open, if somebody can overall share what are the best ways to do class saving and loading the easiest ways I would really glad about it.
I'm not quite sure why do you want to avoid external factories and managers. For me it seems quite natural to extract serialization and not handle it in the model classes themselves. But okay.
What I understood is that your core problem is to load data into this instance. Here's a simple way to achieve this with JAXB.
I'm the author of JAXB2 Basics, a plugin package for JAXB/XJC. It contains the copyable plugin which generates a few copyTo methods in the schema-derived classes.
This will give you methods like copyTo(Object target). With this you can first unmarshal data from XML into some temporary instance and then copyTo(this). Something like:
MyType temporaryInstance = unmarshaller.unmarshal(source, MyType.class).getValue();
temporaryInstance.copyTo(this);
You can add this method to your schema-derived code via code injection or by subclassing.

How to move to XML configurations

I am required to move some of our application configuration classes to XMLs. The classes mainly have enums, which are used by other classes. These enums are extensively used in our application.
For instance, we have classes like
enum ColumnType{
type1("Type1"),type2("type2"),type3("type3")
}
Also we need these types to instantiate classes.
for instance,
Processor p = new StringValueProcessor(ColumnType.type1);
How can I move this to an XML file without changing the dependecies in my application?
Edit:
It is not mandatory to keep these enums and I don't want to compile the code against the classes created from xml. The config needs to be dynamic, that's the whole point of moving to XML, so that we can configure things in XML and there is no need of compiling and re-deploying.
My main concern is to be able to restrict instances for all column types to one and make them accessible throughout my application.
Edit: After thinking over the design for some more time, I have narrowed down to two essential requirements.
1) I would define some xml tags with some properties and I would need to convert it to object
2) I would also define some tags (the way servlets are defined in web.xml) and I would need to initialise the corresponding class
3) I would further define some mapping tags which will map the objects created in step 1) to instances initialised in step 2). This should be converted to java HashMap, where there can be only one instance of objects defined in step 1) but there will be a new instance of objects defined in step 2) for each mapping.
Is there a framework which can provide this functionality out-of-the-box?
You can use the XML files to generate the enums. This has to be done at compile/build time, or you cannot use them in your code like the second example (as they don't exist at compile time)
Why do you want to migrate the enums to XML?
I think the answer your looking for is to use JAXB. It lets you turn XML into POJOs and vice-versa. It even has some functionality for using enums. All you have to do is add some annotations to your java and you can convert to and from XML.
By using annotations, you won't affect any existing functionality.

What is the purpose of Dynamic Bean in ATG

I've read documentation, but there is no definition of the main purpose of Dynamic Bean. I understand how to implement this but dont know why this approach so good.
So could someone tell the situation when it's good to use Dynamic Bean?
Thanks
Dynamic beans typically allow you to get and set fields which may not be explicit members. The most direct comparison is a map - maps allow you to get and set fields without defining them beforehand. However, a dyanamic bean conforms to standard java idioms (getters/setters).
Unlike a hashmap, however, dyanbeans can enforce constraints more readily (and they hide the underlying data structure implementation, so they can be lazy, or make data connections when being set, etc... ) . For example, you can easily add a getter or setter to your dynabean that is explicit, and the code would read very idiomatically and cleanly interact with other bean apis.
public int getCost()
{
if(this.get("cost")==null)
return -1;
return Integer.parseInt(super.get("cost"));
}
The most useful part about dynamic beans in ATG is providing additional DynamicPropertyMapper classes for classes that aren't already covered by it. First, note that you can use the DynamicBeans.setPropertyValue(object, property, value) and DynamicBeans.getPropertyValue(object, property) static methods to set or get properties on an object that don't necessarily correspond with Java bean properties. If the object you're using isn't registered with dynamic beans, it'll try to use Java bean properties by default. Support is provided out of the box to do that with repository items (properties correspond to repository item properties; also applies to the Profile object, naturally), DynamoHttpServletRequest objects (correspond to servlet parameters), maps/dictionaries (correspond to keys), and DOM Node objects (correspond to element attributes followed by the getters/setters of Node).
To add more classes to this, you need to create classes that extend DynamicPropertyMapper. For instance, suppose you want to make HttpSession objects work similarly using attributes with a fallback to the getters and setters of HttpSession. Then you'd implement the three methods from DynamicPropertyMapper, and the getBeanInfo(object) class can be easily implemented using DynamicBeans.getBeanInfo(object) if you don't have any custom BeanInfo or DynamicBeanInfo classes for the object you're implementing this for.
Once you have a DynamicPropertyMapper, you can register it with DynamicBeans.registerPropertyMapper(mapper). Normally this would be put into a static initialization block for the class you're writing the property mapper for. However, if you're making a property mapper for another class out of your control (like HttpSession), you'll want to make a globally-scoped generic service that simply calls the register method in its doStartService(). Then you can add that service to your initial services.

JAX-RS - Can two classes have the same #Path identifier?

I have a webapp that redirects to a particular URI: let's say /service/library. In another bundle, I have a jaxrs server that listens for /service in the URI, and defines some beans to handle the request. There are quite a few beans there already, and one of the classes is already implemented to handle requests for /service/library. I am trying to create a new class that also handles requests for /service/library, but with a different absolute URI path, for example: /service/library/mynewlibrary. My question is, is it possible to define the same #Path identifier in two classes, or must they be unique, in other words, will I need to use a URI like /service/mylibrary for my new class implementation instead of implementing a second class that also uses the same #Path identifier? I am pretty new to JAX-RS, so I hope my question makes sense!
Thanks!
It's possible to have two #Path annotations that match the URI. In your case, if servlet-mapping is service, you may have #Path("/library") and #Path("library/mynewlibrary").
When request arrives, the matching paths are sorted in descending order, so the second class should be called, when a request with /service/library/mynewlibrary arrives.
It's most certainly possible to have two methods with the same #Path annotation, e.g., if they're distinguished by other means (such as HTTP method or #Consumes annotation). The #Path on a class acts as a default/root for the #Paths on the class's methods. Moreover, it's not a problem at all if you've got one path that is “within” another; JAX-RS specifies that the most specific match possible is used. (I prefer to not do it that way, instead having the “outer” class return a reference to the “inner” class on a suitable partial match, so that every path has a traceable route to responsibility that definitely leads to a single class. That requires a fairly different way of arranging the #Path annotations though.)
But if you've ended up with two methods that can serve the same incoming request, you've got a clash and the JAX-RS implementation will be free to pick which one to use (in an implementation-dependent manner). That's probably not what you want, as computers tend to make bad decisions when given a free choice.
You can achieve your goal to have /service/library/mynewlibrary using below configuration.
In your existing class you have /service/library configured at class level so you can configure /service at class level in new class you are adding and then at method level configure /library/mynewlibrary.
This way it will not have same path for both classes and your goal is also achieved. I tried this and it works.

Categories

Resources