Created
April 17, 2017 13:15
-
-
Save elaatifi/47c4031401840fa3008a94485e2e59cf to your computer and use it in GitHub Desktop.
hybris has a special setters and getters for Localized propertires, where getter & setters have an additional Locale parameter. The following test case show an example of how to map this kind of properties to Map where the key is the local with default auto mapping
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class LocalizedStringTestCases { | |
ConfigurableMapper mapper = new ConfigurableMapper() { | |
@Override | |
protected void configure(MapperFactory factory) { | |
factory.classMap(ProductModel.class, ProductDTO.class).byDefault().register(); | |
} | |
@Override | |
protected void configureFactoryBuilder(DefaultMapperFactory.Builder factoryBuilder) { | |
factoryBuilder.propertyResolverStrategy(new CustomPropertyResolver(Locale.FRENCH, Locale.ENGLISH)); | |
factoryBuilder.useAutoMapping(true); | |
factoryBuilder.classMapBuilderFactory(new CustomClassMapBuilder.Factory()); | |
} | |
}; | |
@Test | |
public void testLocalizedString() { | |
ProductModel productModel = new ProductModel(); | |
productModel.setCode("0001"); | |
productModel.setName("Product 0001"); | |
productModel.setName(Locale.FRENCH, "Produit 0001"); | |
productModel.setDescription("Product 0001 description"); | |
productModel.setDescription(Locale.FRENCH, "Description du Produit 0001"); | |
productModel.setPrice(1.0); | |
productModel.setPrice(Locale.FRENCH, 1.0); | |
final ProductDTO productDTO = mapper.map(productModel, ProductDTO.class); | |
Assert.assertEquals(productDTO.getCode(), productModel.getCode()); | |
Assert.assertNotNull(productDTO.getName()); | |
Assert.assertEquals(productDTO.getName().get("fr"), productModel.getName(Locale.FRENCH)); | |
Assert.assertEquals(productDTO.getName().get("en"), productModel.getName(Locale.ENGLISH)); | |
Assert.assertNotNull(productDTO.getDescription()); | |
Assert.assertEquals(productDTO.getDescription().get("fr"), productModel.getDescription(Locale.FRENCH)); | |
Assert.assertEquals(productDTO.getDescription().get("en"), productModel.getDescription(Locale.ENGLISH)); | |
Assert.assertNotNull(productDTO.getPrice()); | |
Assert.assertEquals(productDTO.getPrice().get("fr"), productModel.getPrice(Locale.FRENCH)); | |
Assert.assertEquals(productDTO.getPrice().get("en"), productModel.getPrice(Locale.ENGLISH)); | |
} | |
public static class ProductDTO { | |
private String code; | |
private Map<String,String> name; | |
private Map<String,String> description; | |
private Map<String,Double> price; | |
public Map<String, Double> getPrice() { | |
return price; | |
} | |
public void setPrice(Map<String, Double> price) { | |
this.price = price; | |
} | |
public String getCode() { | |
return code; | |
} | |
public void setCode(String code) { | |
this.code = code; | |
} | |
public Map<String, String> getName() { | |
return name; | |
} | |
public void setName(Map<String, String> name) { | |
this.name = name; | |
} | |
public Map<String, String> getDescription() { | |
return description; | |
} | |
public void setDescription(Map<String, String> description) { | |
this.description = description; | |
} | |
} | |
public static class ProductModel { | |
private String code; | |
private Map<Locale,String> name = new HashMap<Locale, String>(); | |
private Map<Locale,String> description = new HashMap<Locale, String>(); | |
private Map<Locale, Double> price = new HashMap<Locale, Double>(); | |
public String getCode() { | |
return code; | |
} | |
public void setCode(String code) { | |
this.code = code; | |
} | |
public void setName(String name) { | |
setName(Locale.ENGLISH, name); | |
} | |
public void setName(Locale locale, String name) { | |
this.name.put(locale, name); | |
} | |
public String getName() { | |
return name.get(Locale.ENGLISH); | |
} | |
public String getName(Locale locale) { | |
return this.name.get(locale); | |
} | |
public void setDescription(String description) { | |
setDescription(Locale.ENGLISH, description); | |
} | |
public void setDescription(Locale locale, String description) { | |
this.description.put(locale, description); | |
} | |
public String getDescription() { | |
return getDescription(Locale.ENGLISH); | |
} | |
public String getDescription(Locale locale) { | |
return this.description.get(locale); | |
} | |
public void setPrice(Double price) { | |
setPrice(Locale.ENGLISH, price); | |
} | |
public void setPrice(Locale locale, Double price) { | |
this.price.put(locale, price); | |
} | |
public Double getPrice() { | |
return getPrice(Locale.ENGLISH); | |
} | |
public Double getPrice(Locale locale) { | |
return this.price.get(locale); | |
} | |
} | |
public static class CustomPropertyResolver extends IntrospectorPropertyResolver { | |
private Locale[] locales; | |
private final Pattern readPattern; | |
private final Pattern writePattern; | |
private final boolean includeJavaBeans; | |
private int writeMethodRegexCaptureGroupIndex; | |
private int readMethodRegexCaptureGroupIndex; | |
public CustomPropertyResolver(Locale... locales) { | |
super(false); | |
this.includeJavaBeans = false; | |
this.readPattern = Pattern.compile("is|get([0-9a-zA-Z_]+)"); | |
this.writePattern = Pattern.compile("set([0-9a-zA-Z_]+)"); | |
this.readMethodRegexCaptureGroupIndex = 1; | |
this.writeMethodRegexCaptureGroupIndex = 1; | |
this.locales = locales; | |
} | |
@Override | |
protected void collectProperties(Class<?> type, Type<?> referenceType, Map<String, Property> properties) { | |
final Class[] setterParamsTypes = {Locale.class, String.class}; | |
final Class[] getterParamsTypes = {Locale.class}; | |
HashSet<String> localized = new HashSet<String>(); | |
Map<String, Property.Builder> collectedMethods = new LinkedHashMap<String, Property.Builder>(); | |
for (Method m : type.getMethods()) { | |
if (Arrays.equals(m.getParameterTypes(), getterParamsTypes)) { | |
Matcher readMatcher = readPattern.matcher(m.getName()); | |
if(readMatcher.matches()) { | |
String name = readMatcher.group(readMethodRegexCaptureGroupIndex); | |
name = uncapitalize(name); | |
localized.add(name); | |
for (Locale locale : locales) { | |
String localizedName = localizedPropertyName(name, locale); | |
Property.Builder builder = collectedMethods.get(localizedName); | |
if (builder == null) { | |
builder = new Property.Builder(TypeFactory.resolveValueOf(type, referenceType), localizedName); | |
collectedMethods.put(localizedName, builder); | |
builder.type(m.getReturnType()); | |
} | |
builder.getter(m.getName()+"("+Locale.class.getName()+".forLanguageTag(\""+locale.getLanguage()+"\"))"); | |
} | |
} | |
} | |
else if (m.getParameterTypes().length == 2 && Locale.class.equals(m.getParameterTypes()[0])) { // Localized String | |
Matcher writeMatcher = writePattern.matcher(m.getName()); | |
if (writeMatcher.matches()) { | |
String name = writeMatcher.group(writeMethodRegexCaptureGroupIndex); | |
name = uncapitalize(name); | |
//System.out.println("Match LocalizedString setter, "+name); | |
localized.add(name); | |
for (Locale locale : locales) { | |
String localizedName = localizedPropertyName(name, locale); | |
Property.Builder builder = collectedMethods.get(localizedName); | |
if (builder == null) { | |
builder = new Property.Builder(TypeFactory.resolveValueOf(type, referenceType), localizedName); | |
collectedMethods.put(localizedName, builder); | |
builder.type(m.getParameterTypes()[1]); | |
} | |
builder.setter(m.getName()+"("+Locale.class.getName()+".forLanguageTag(\""+locale.getLanguage()+"\"), %s)"); | |
} | |
} | |
} | |
else if (m.getParameterTypes().length == 0 && m.getReturnType() != null && m.getReturnType() != Void.TYPE) { | |
Matcher readMatcher = readPattern.matcher(m.getName()); | |
if (readMatcher.matches()) { | |
String name = readMatcher.group(readMethodRegexCaptureGroupIndex); | |
if (name != null) { | |
name = uncapitalize(name); | |
Property.Builder builder = collectedMethods.get(name); | |
if (builder == null) { | |
builder = new Property.Builder(TypeFactory.resolveValueOf(type, referenceType), name); | |
collectedMethods.put(name, builder); | |
} | |
builder.getter(m); | |
} else { | |
throw new IllegalStateException("the configured readMethod regex '" + readPattern + | |
"' does not define group (1) containing the property's name"); | |
} | |
} | |
} else if (m.getParameterTypes().length == 1) { | |
Matcher writeMatcher = writePattern.matcher(m.getName()); | |
if (writeMatcher.matches()) { | |
String name = writeMatcher.group(writeMethodRegexCaptureGroupIndex); | |
if (name != null) { | |
name = uncapitalize(name); | |
Property.Builder builder = collectedMethods.get(name); | |
if (builder == null) { | |
builder = new Property.Builder(TypeFactory.resolveValueOf(type, referenceType), name); | |
collectedMethods.put(name, builder); | |
} | |
builder.setter(m); | |
} else { | |
throw new IllegalStateException("the configured writeMethod regex '" + writePattern + | |
"' does not define group (1) containing the property's name"); | |
} | |
} | |
} else { | |
} | |
} | |
for (Map.Entry<String, Property.Builder> entry : collectedMethods.entrySet()) { | |
Property property = entry.getValue().build(this); | |
//processProperty(property.getName(), property.getType().getRawType(), entry.getValue().getReadMethod(), entry.getValue().getWriteMethod(), type, referenceType, properties); | |
if(!localized.contains(entry.getKey())) | |
properties.put(property.getName(), property); | |
} | |
if (includeJavaBeans) { | |
super.collectProperties(type, referenceType, properties); | |
} | |
} | |
private String localizedPropertyName(String name, Locale locale) { | |
return name+"__ls__"+locale; | |
} | |
/** | |
* Converts the first character of a String to lowercase | |
* | |
* @param string | |
* @return the original String with the first character converted to lowercase | |
*/ | |
protected String uncapitalize(String string) { | |
return string.substring(0, 1).toLowerCase() + string.substring(1, string.length()); | |
} | |
} | |
public static class CustomClassMapBuilder<A, B> extends ClassMapBuilder<A, B> { | |
protected CustomClassMapBuilder(Type<A> aType, Type<B> bType, MapperFactory mapperFactory, PropertyResolverStrategy propertyResolver, DefaultFieldMapper... defaults) { | |
super(aType, bType, mapperFactory, propertyResolver, defaults); | |
} | |
@Override | |
public ClassMapBuilder<A, B> byDefault(DefaultFieldMapper... withDefaults) { | |
super.byDefault(withDefaults); | |
final Map<String, Property> aProperties = getPropertyResolver().getProperties(getAType().getRawType()); | |
final Map<String, Property> bProperties = getPropertyResolver().getProperties(getBType().getRawType()); | |
for (final String propertyName : aProperties.keySet()) { | |
if(propertyName.contains("__ls__")) { | |
final String[] strings = propertyName.split("__ls__"); | |
final Property property = bProperties.get(strings[0]); | |
if(property != null) { | |
if( property.getRawType().equals(Map.class)) { | |
//System.out.println("Found Localized property match with Map"); | |
fieldMap(propertyName, strings[0]+"['"+strings[1]+"']").add(); | |
} | |
} | |
} | |
} | |
for (final String propertyName : bProperties.keySet()) { | |
if(propertyName.contains("__ls__")) { | |
final String[] strings = propertyName.split("__ls__"); | |
final Property property = aProperties.get(strings[0]); | |
if(property != null) { | |
if( property.getRawType().equals(Map.class)) { | |
fieldMap(strings[0]+"['"+strings[1]+"']", propertyName).add(); | |
} | |
} | |
} | |
} | |
return this; | |
} | |
public static class Factory extends ClassMapBuilderFactory { | |
@Override | |
protected <A, B> ClassMapBuilder<A, B> newClassMapBuilder(Type<A> aType, Type<B> bType, MapperFactory mapperFactory, PropertyResolverStrategy propertyResolver, DefaultFieldMapper[] defaults) { | |
return new CustomClassMapBuilder<A, B>(aType, bType, mapperFactory, propertyResolver, defaults); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
__ls__
: is a "hackish" string sperator used to create virtual property (to separate property name and locale)