Conception problem on generic implementation - java

Context : Java using Guice 3.0
'Hi everybody, I'm trying to construct a decent converter library for my web application.
Converter allow me to convert from an unknown type to another type.
To convert type, I'm using a converter registry with Guice MultiBinder like this one (following #Ivan Sopov's implementation)
An example might be more explicit :
**NOTICE : this is not a working example**
//"obj" is an object with unknowed type, and we want to convert it to another type)
Converter c = converterRegistry.getConverter(obj.getClass(),type.getClass());
Object t = c.convert(obj); //obj is now converted !
I can have many kind of Converter : StringToInteger, StringToDouble, etc ; for those simple one I have no problem.
public interface Converter<F,T>{
public T convert(F from);
}
public class StringToInteger implements Converter<String,Integer>{
public Integer convert(String from){
return Integer.valueOf(from);
}
}
Problems come when I have to implement Converter that needs some more parameters (specific information to convert a type).
For example : DateToString converter
In this case I would have the current user Locale to format the Date into String correctly.
Currently I'm badly solving the problem using another parameter to my Converter interface like that :
public interface Converter<F,T>{
public T convert(F from, ConverterData data);
}
public class ConverterData{
private Locale locale;
//... many other object that can be usefull for other converter...
}
public class DateToString implements Converter<Date,String>{
public String convert(Date from, ConverterData data){
//using data.getLocale() to convert the Date to String and return it
}
}
Now, I'm searching a better solution to improve the code. I thought about some possible solution using Guice but I'm not totally convinced...
Here is one of them :
public class DateToString implements Converter<Date,String>{
private Provider<Locale> providerLocale;
#Inject
public DateToString(Provider<Locale> providerLocale){
this.providerLocale = providerLocale;
}
public String convert(Date from){
//using providerLocale.get() to convert the Date
}
}
Here, I'm using a Provider cause a converter could be in a #Singleton...
(maybe I'm wrong in using a Provider ?)
- How should I do this ?
Well, I tried to explain my problem at best. I hope someone will take time to read that :)
I'm waiting for your help, Thanks in advance !
PS : Hard to find a title for this post, any suggestion are welcome!

It looks like you want a Converter that is configured by the locale state of the current request.
You are on the right track with the Provider. The reason you give sounds off to me. I'll explain.
Because you will be using your converterRegistry to get the Converter it looks like you'll be using the same object for each request.
A provider is factory that uses guice to supply values. Because you want to configure the DataToString converter with per-request state this allows you to configure the locale for each call to the convert method on the reused object.
Next, you need to create a guice provider class or method of the Local. If you already know how to do that you are done.
To more fully integrate guice I suggest you use Guice-servlet to plug it into your requests: http://code.google.com/p/google-guice/wiki/Servlets

Related

Instantiate proper strategy with Java and Spring Boot

I have the following situation:
I have to validate a Token using (for now) 2 different strategies, they both do the same thing (check if the token is valid) but in different ways.
My current way of dealing with the strategy instantiation looks like this:
#Service
public class ValidationService {
private Map<ValidationType, ValidationStrategy> validationMap = new HashMap<>();
public ValidationService() {
validationMap.put(ValidationType.A, new AValidationStrategy());
validationMap.put(ValidationType.B, new BValidationStrategy());
}
public void validate(ValidationType type, String token) {
ValidationStrategy strategy = validationMap.get(type);
if(strategy == null) {
strategy = new NoValidationStrategy();
}
strategy.validate(token);
}
}
My question is: Is there a prettier way to set up the proper validation according to the ValidationType enum? Because the constructor would grow more and more as new validation strategies would be added in the system.
I thought that maybe I could keep that Map<> variable and add new Strategy instances when the ValidationService bean would be created by some sort of Spring Boot configuration, but I don't know how I could access the Bean after its instantiation by Spring Boot.
Help me out if you have a better way of doing this! :)
PS: Any code snippets or useful links would be greatly appreciated!
Absolutely, one option is Reflection. Every ValidationStrategy could define a ValidationType either as a Method or through an Annotation, assuming ValidationType is an enumeration. You could then find all ValidationStrategy and group them to a Map based on type. This would solve the problem of having to update the map every time a new validation strategy is added.

Entity to DTO conversion in a J2EE application using an enum?

This is one of those topics I don't even know how to search in google (tried already, most of the results were for C#), so here I go:
I'm messing around with our huge application, trying to get to work a brand new DAO/Entity/Service/DTO.. euh...thing. I've been left more or less on my own, and, again, more or less, I'm getting to understand some of the hows and maybe one or two of the whys.
The thing is that I got all, the way "up", from the DB to the Service:
I got a DAO class which executes a query stored on an Entity class. After executing it, it returns the Entity with the values.
The service receives the Entity and, somehow, transforms the Entity to a DTO and returns it to whenever is needed.
My problem is with the "somehow" thing the code goes like this:
DTOClass dto = ClassTransformerFromEntityToDTO.INSTANCE.apply(entityQueryResult);
I went into ClassTransformerFromEntityToDTO and found this:
public enum ClassTransfomerFromEntityToDTO implements Function<EntityClass,DTO Class> ) {
INSTANCE;
#Override
public DTOClass apply(EntityClass entityInstance) {
/*Code to transform the Entity to DTO and the return*/
}
}
The class that this... thing, implements, is this:
package com. google .common . base;
import com. google .common . annotations. GwtCompatible ;
import javax. annotation .Nullable ;
#GwtCompatible
public abstract interface Function <F , T >
{
#Nullable
public abstract T apply (#Nullable F paramF) ;
public abstract boolean equals (#Nullable Object paramObject) ;
}
I'm in the classic "everyone who where at the beginning of the project fled", and no one knows why is this or what is this (The wisest one told me that maybe it had something to do with Spring), so, I have two main questions (which can be more or less answered in the same side):
1) What's this? What's the point of using an enum with a function to make a conversion?
2) What's the point of this? Why can I just make a class with a single function and forget about this wizardry?
not sure there's much to answer here... And I'm adding an answer to illustrate my thoughts with some code I've seen, but that you have is horrible. I've actually seem similar stuff. My guess is that that codes actually precedes Spring. It's used as some sort of Singleton.
I have seen code like this, which is worse:
public interface DTO {
find(Object args)
}
public class ConcreteDTO1 implements DTO {
...
}
public class ConcreteDTO2 implements DTO {
...
}
public enum DTOType {
CONCRETE_DTO1(new ConcreteDTO1(someArgs)),
CONCRETE_DTO2(new ConcreteDTO2(someOtherArgs))
private DTO dto;
public DTOType(DTO dto) {
this.dto = dto;
}
public DTO dto() {
return dto;
}
}
and then the DTOs are basically accessed through the Enum Type:
DTOType.CONCRETE_DTO1.dto().find(args);
So everyone trying to get hold of a DTO accesses it through the enum. With Spring, you don't need any of that. The IoC container is meant to avoid this kind of nonsense, that's why my guess is that it precedes Spring, from some ancient version of the app when Spring was not there. But it could be that someone was wired to do such things regardless of whether Spring was already in the app or not.
For that kind of stuff you're trying to do, you're better of with the Visitor pattern. Here's an example from a different answer: passing different type of objects dynamically on same method
It's me. From the future.
Turns out that this construct is a propossed Singleton Implementation, at least on "Effective Java 2nd edition".
So, yeah, Ulise's guess was well oriented.

Map a collection with parameter with mapstruct

To map a certain object with mapstruct I need some custom post processing which needs an additional parameter to do it's work:
#Mapper
public abstract class AlertConfigActionMapper {
#Mappings({ #Mapping(target = "label", ignore = true)})
public abstract AlertConfigActionTO map (AlertConfigAction action, Locale userLanguage);
#AfterMapping
public void setLabel (AlertConfigAction action, #MappingTarget AlertConfigActionTO to, Locale userLanguage) {
for (AlertConfigActionLabel label : action.getAlertConfigActionLabels()) {
if (label.getLanguage().equals(userLanguage)) {
to.setLabel(label.getLabel());
break;
} else if (label.getLanguage().equals(Locale.ENGLISH)) {
to.setLabel(label.getLabel());
}
}
}
}
This works just fine.
The problem starts when I add following method to this mapper:
public abstract ArrayList<AlertConfigActionTO> mapList (List<AlertConfigAction> actions, Locale userLanguage);
I need to pass this parameter (userLanguage) as well but mapstruct seems to 'break down' in this case: I generates following code for this part (which naturally gives a compilation error):
#Override
public List<AlertConfigActionTO> mapList(List<AlertConfigAction> actions, Locale userLanguage) {
if ( actions == null && userLanguage == null ) {
return null;
}
List<AlertConfigActionTO> list = new List<AlertConfigActionTO>();
return list;
}
I'm sure it is related to the parameter since if I remove it (from all mapping methods) then the mapList method is generated correctly.
What is needed to be done to allow custom parameters in this case?
What you describe is not possible (yet). Could you open a feature request in our issue tracker? We should provide means of denoting parameters as some sort of "context" which is passed down the call stack.
As a work-around for the time being, you might take a look at using a ThreadLocal which you set before invoking the mapping routine and which you access in your after-mapping customization. It's not elegant - and you need to make sure to clean up the thread local to avoid memory leaks - but it should do the trick.
I know that this question is quiet old, but I run into this issue, and starting at version 1.2 of mapstruct you can resolve it using #Context
So declaring the mapping for the list need to be like this :
public abstract ArrayList<AlertConfigActionTO> mapList (List<AlertConfigAction> actions, #Context Locale userLanguage);
Now, you juste need to add another non abstract mapping like this :
public AlertConfigActionTO mapConcrete (AlertConfigAction action, #Context Locale userLanguage){
return map (action, userLanguage);
}
I don't think it is possible. At least not that way. Problem is that you prepare interface/abstract class - and rest is done by the engine. And that engine expects methods with one parameter... There are decorators, but they go the same way. I would try to inject language. Create bean, mark it as session scoped, and find out. With Spring, you would use ScopedProxyMode for that... Not sure how that goes with CDI.
Other option is more workaround, then solution - maybe that AlertConfigAction can pass that information?

How is Spring's DataBinder used to convert a plain parameter value?

I've been digging through the Spring DataBinder code and docs while answering this question and i've noticed the DataBinder constructor docs mentionioning :
target - the target object to bind onto (or null if the binder is just
used to convert a plain parameter value)
I've been searching around and haven't found such a usage and it really made me curious. Would appreciate any insight related to :
How would such a data binder be used with a null target to convert a plain parameter value?
Or what does it actually mean to convert a plain parameter value in this context?
Is it also applicable to Spring MVC? (since i noticed it mentioned in WebDataBinder's constructor docs as well).
I have been done some digging in the Spring Framework source, searching for usages with null parameter as you described. Since I was not aware of this kind of usage either, looking at the testcases to understand things better was my way to go.
The test class for DataBinder is (not surprisingly) DataBinderTests.
I am going to paste a usage example here, along with the link to github where I found the code, for reference:
For your first question, the answer seems if you use a DataBinder with null constructor parameter, it means that you just want to use the conversion facility, without the data binding mechanism (since we have not passed an object to bind values to).
This pretty explanatory testcase shows this type of usage, creating a DataBinder with null, setting a DefaultFormattingConversionService to the dataBinder and registering a custom editor after that.
You can add a custom converter with the addConverter method if you want a different String representation after converting your bean.
#Test
public void testConversionWithInappropriateStringEditor() {
DataBinder dataBinder = new DataBinder(null);
DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
dataBinder.setConversionService(conversionService);
dataBinder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
NameBean bean = new NameBean("Fred");
assertEquals("ConversionService should have invoked toString()", "Fred", dataBinder.convertIfNecessary(bean, String.class));
conversionService.addConverter(new NameBeanConverter());
assertEquals("Type converter should have been used", "[Fred]", dataBinder.convertIfNecessary(bean, String.class));
}
For reference, here is the code of NameBeanConverter (also from the test class)
public static class NameBeanConverter implements Converter<NameBean, String> {
#Override
public String convert(NameBean source) {
return "[" + source.getName() + "]";
}
}
Source: https://github.com/spring-projects/spring-framework/blob/d5ee787e1e6653257720afe31ee3f8819cd4605c/spring-context/src/test/java/org/springframework/validation/DataBinderTests.java#L598-L609
I think the above explanation was an answer for the first two questions:
How would such a data binder be used with a null target to convert a plain parameter value?
Or what does it actually mean to convert a plain parameter value in this context?
For your third question, unfortunately, I have not found any usable testcase like above, but going through the WebDataBinder's code make me think of there is no "added value" compared to DataBinder in terms of a null constructor parameter, so you can use the conversion facility through the WebDataBinder as well.
You probably know that you can bind your web request fields to your backing bean, adding conversion (e.g. converting a particularly formatted date to an actual Date field object on the backing bean) etc etc, but I don't want to describe this in more detail as this was not your point with the question I guess.
Lastly, I found this article very useful about how the WebDataBinder could be used: http://www.intertech.com/Blog/spring-frameworks-webdatabinder/
You can think of DataBinder as filter or handler that all request parameters go thorough before they get consumed. To make use of the DataBinder functionality you need to implement a method in your controller class with "#InitBinder" annotation. For example:
#InitBinder
public void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
// bind empty strings as null
binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
}
As you see, all you need to do in the method is register CustomEditor for a specific data type.
In Spring MVC, a DataBinder with a null target is automatically used in a case like this :
#RequestMapping(method = RequestMethod.GET)
public String showHome(#RequestParam("date") Date date) {
return "home";
}
In this case, the created DataBinder has an objectName "date" and a null target.

Java type conversion where types are not known until runtime

I'm trying to write a data access layer for an AJAX web project. This DAL has to convert data coming in via an AJAX servlet to objects that can be passed to a PreparedStatement for execution.
Data in the AJAX servlet, retrieved by using HttpServletRequest.getParameter(...), come in as strings.
In each data class, I have a known set of fields as well as their data types, e.g. CustomerId(integer), CustomerName(string).
I can of course write a method in the Customer class to handle the conversion, but this means I have to do it for every data object's class. I would much rather have a generic method that does conversion, e.g.
Object convert(String value, Class<?> targetType) { ... }
Can anyone point me in the right direction?
Create an utility class with all conversion methods you would like to use. Inside its static initializer, make use of reflection to collect all those methods by parameter type and return type in a map. Then, in the convert() method just pick the method which suits the given source and target type and invoke it. Make use of generics to fix the return type to be the same as the target type:
public static <T> T convert(Object from, Class<T> to)
You can find an example in this article.
But as bmargulies pointed out, JSON is also an interesting option. You could let ajax to send all parameters as one JSON string. Then, you can use a JSON-to-Javabean converter like Google Gson to convert the JSON string to a fullworthy Javabean like Customer. It'll be as simple as:
String jsondata = request.getParameter("jsondata");
Customer customer = new Gson().fromJson(jsondata, Customer.class);
// ...
See also this answer for another example.
There are JSON libraries that will do data type conversion. Jackson is one. Or, you could code the whole think using a JAX-RS service framework instead of a raw servlet, and it will take care of all this for you. Apache CXF is one framework that contains this support. Since you are asking for a generic solution, why not use one that's already out there.
We do this exact thing using a plethora of static converters in a utility class. It isn't elegant but it sure is easy and effective.
class Util {
public static Long StringToLong(String s) { ... }
public static Integer StringToInt(String s) { ... }
public static Date StringToDate(String s) { ... }
public static Date StringToDateYYMMDD(String s) { ... }
public static BigDecimal StringToBigDecimal(String s) { ... }
// etc ad naseum
}
Since you want to use the parameters in your PreparedStatement, why do you have to convert them at all?
When using setString(index, parameter) SQL will be happy to do the conversion for you.
Thus the only thing you might want to do is some kind of validation that the input is really valid (or you could even leave this part to your SQL engine which will throw an exception if it doesn't understand you.

Categories

Resources