Skip to content

Instantly share code, notes, and snippets.

@elaatifi
Created April 17, 2017 13:15
Show Gist options
  • Save elaatifi/47c4031401840fa3008a94485e2e59cf to your computer and use it in GitHub Desktop.
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
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);
}
}
}
}
@elaatifi
Copy link
Author

__ls__ : is a "hackish" string sperator used to create virtual property (to separate property name and locale)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment