mapping of non-iterable to iterable in mapstruct - java

I am trying to map a non-iterable value i.e. String to a list of string using mapstruct.
So I am using
#Mapping(target = "abc", expression = "java(java.util.Arrays.asList(x.getY().getXyz()))")
Here abc is List<String>
xyz is a String
But for this i need to check for null explicitly.
Is there any better way of maaping a non-iterable to iterable by converting non iterable to iterable.

Here is an example for non iterable-to-iterable:
public class Source {
private String myString;
public String getMyString() {
return myString;
}
public void setMyString(String myString) {
this.myString = myString;
}
}
public class Target {
private List<String> myStrings;
public List<String> getMyStrings() {
return myStrings;
}
public void setMyStrings(List<String> myStrings) {
this.myStrings = myStrings;
}
}
#Qualifier
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.SOURCE)
public #interface FirstElement {
}
public class NonIterableToIterableUtils {
#FirstElement
public List<String> first(String in ) {
if (StringUtils.isNotEmpty(in)) {
return Arrays.asList(in);
} else {
return null;
}
}
}
#Mapper( uses = NonIterableToIterableUtils.class )
public interface SourceTargetMapper {
SourceTargetMapper MAPPER = Mappers.getMapper( SourceTargetMapper.class );
#Mappings( {
#Mapping( source = "myString", target = "myStrings", qualifiedBy = FirstElement.class )
} )
Target toTarget( Source s );
}
public class Main {
public static void main(String[] args) {
Source s = new Source();
s.setMyString("Item");
Target t = SourceTargetMapper.MAPPER.toTarget( s );
System.out.println( t.getMyStrings().get(0));
}
}

There is a iterable-to-non-iterable example in the MapStruct examples repository. Addtionally there is a pending pull request for non-iterable-to-iterable.
In a nutshell you can use a custom method that would do the mapping. You can also use #Qualifier to have more granural control

Add an empty default method in the mapper, e.g. AnimalMapper.toLions(), and overwrite the default method in a mapper decorator, e.g. AnimalMapperDecorator. It works in my test.
#Repository
#Mapper(componentModel = "spring")
#DecoratedWith(AnimalMapperDecorator.class)
public interface AnimalMapper {
default List<Lion> toLions(Jungle jungle) {
return null;
}
}
public abstract class AnimalMapperDecorator implements AnimalMapper {
#Autowired
#Qualifier("delegate")
private AnimalMapper delegate;
#Override
public List<Lion> toLions(Jungle jungle) {
List<Lion> lions = new ArrayList<>();
Lion king = getKing(jungle);
Lion queen = getQueen(jungle);
Lion leo = getLeo(jungle);
lions.add(king); lions.add(queen); lions.add(leo);
return lions;
}
}
class Test {
#Autowired
private AnimalMapper animalMapper;
public void test() {
Jungle jungle = generateJungle();
List<Lion> lions = animalMapper.toLions(jungle);
// Assert lions
}
}

Related

mapstruct wrapper type and generics

I am trying to map JsonNullable<List<ChildRequestTO> to Nullable<List<ChildRequestDO>> (see full code below) with mapstruct 1.4.2.Final and I am facing the following error: error: Nullable<List<ChildRequestDO>> does not have an accessible constructor. If I add a constructor for Nullable like
public Nullable(T value) {
this.value = value;
this.isPresent = true;
}
then I get the following error error: Unmapped target property: "value". Mapping from property "JsonNullable<List<ChildRequestTO>> products" to "Nullable<List<ChildRequestDO>> products".
How do I map complex wrapped types in a generic way?
The following mapping code (part of ChildRequestMapper class and applied in ObjectRequestMapper) solves the problem but I want to solve it in a more generic way:
#Named("mappingHelper")
default Nullable<List<ChildRequestDO>> customMapToDOs(JsonNullable<List<ChildRequestTO>> input) {
if (JsonNullable.undefined().equals(input)) {
return Nullable.undefined();
}
if (input.get() == null) {
return Nullable.of(null);
}
var output= input.get()
.stream()
.map(this::mapToDO)
.collect(Collectors.toList());
return Nullable.of(output);
}
Changing the NullableMapper to the code below does not work/compile because I do not know how to tell mapstruct to look for the appropriate mapper to map from T to X.
public static <T, X> Nullable<X> jsonNullableToNullable(JsonNullable<T> jsonNullable) {
if (jsonNullable.isPresent()) {
return Nullable.of(jsonNullable.get());
}
return Nullable.undefined();
}
Full code:
#Mapper(
unmappedTargetPolicy = ReportingPolicy.ERROR,
uses = {ChildRequestMapper.class, NullableMapper.class}
)
public interface ObjectRequestMapper {
#Mapping(target = "slots", source = "slots", qualifiedByName = "mapToSlotDOs")
ModifyObjectRequestDO mapToDO(ModifyObjectRequestTO input);
}
#Mapper(unmappedTargetPolicy = ReportingPolicy.ERROR)
public interface ChildRequestMapper {
ChildRequestDO mapToDO(ChildRequestTO input);
}
public class NullableMapper {
public static <T> Nullable<T> jsonNullableToNullable(JsonNullable<T> jsonNullable) {
if (jsonNullable.isPresent()) {
return Nullable.of(jsonNullable.get());
}
return Nullable.undefined();
}
}
public class ModifyObjectRequestTO {
private JsonNullable<String> name = JsonNullable.undefined();
private JsonNullable<List<ChildRequestTO>> children = JsonNullable.undefined();
}
public class ModifyObjectRequestDO {
private Nullable<String> name = Nullable.undefined();
private Nullable<List<ChildRequestDO>> children = Nullable.undefined();
}
public class Nullable<T> {
private static final Nullable<?> UNDEFINED = new Nullable<>(null, false);
private final T value;
private final boolean isPresent;
private Nullable(T value, boolean isPresent) {
this.value = value;
this.isPresent = isPresent;
}
public static <T> Nullable<T> undefined() {
#SuppressWarnings("unchecked")
Nullable<T> t = (Nullable<T>) UNDEFINED;
return t;
}
public static <T> Nullable<T> of(T value) {
return new Nullable<T>(value, true);
}
public T get() {
if (!isPresent) {
throw new NoSuchElementException("Value is undefined");
}
return value;
}
public boolean isPresent() {
return isPresent;
}
}

how to get annotation values from Predicate reference?

here is the source codes
#Retention(RetentionPolicy.RUNTIME)
public #interface PredicateMeta {
String name();
int data();
String operator();
}
public class AnnotationTest {
public static void main(String[] args) {
Predicate p = getPred();
// how to get annotation values of data, name and operator??
}
public static Predicate getPred() {
#PredicateMeta(data = 0, name = "name", operator = "+")
Predicate p = (o) -> true;
return p;
}
}
How to get the values of annotation?
Also, will it be slow at runtime using annotations than using values from encapsulated fields?
You cant do this with lambdas.
If you try to get p.getClass().getAnnotatedInterfaces(), you will see that there is no annotations.
This is the only way to make this work:
first of all you must give your annotation #Target(ElementType.TYPE_USE)
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE_USE)
#interface PredicateMeta {
String name();
int data();
String operator();
}
then use anonymous class:
public static Predicate getPred() {
return new #PredicateMeta(data = 0, name = "name", operator = "+")Predicate() {
#Override
public boolean test(Object o) {
return true;
}
};
}
so when you call this, you can get your annotation and its parameters:
p.getClass().getAnnotatedInterfaces()[0].getAnnotation(PredicateMeta.class)

is it possible to check a variable with a list of method?

I want to pass a string into a series of method. These method will check whether the string have all properties needed. so, if the string didn't meet the requirement on one validator method, it will return false.
example :
input : "customerid=cu01","name=someone","phone=+628770xxxxx","address=somewhere","balance=500000"
output : true
another example :
"customerid=cu01","name=someone","address=somewhere","balance=200000"
output : false (no phone number)
Is it possible to create a list of validator class like this
List<Validator> val = new ArrayList<Validator>();
val.add(ValidatorA);
val.add(ValidatorB);
etc.
so i can check the string with that list of validator. i just want to know, is it possible to check a string with a list of validator like that? i'm doing this because it will be easier to add another validator if needed someday.
thanks
You could use the decorator pattern.
Take a look at this example I think it suits your usecase:
http://blog.decarufel.net/2009/09/using-decorator-or-wrapper-design.html
http://sourcemaking.com/design_patterns/decorator
public abstract class ValidationObject {
String description = "no particular";
public String getDescription(){
return description;
}
}
public class Account extends ValidationObject {
public Account(){
description = "account";
}
}
public class Book extends ValidationObject {
public Book () {
description = "book";
}
}
public abstract class ValidationObjectDecorator extends ValidationObject {
public abstract String getDescription();
}
public class ValidationOne extends ValidationObjectDecorator {
private ValidationObject account;
public ValidationOne (ValidationObject g) {
account = g;
}
#Override
public String getDescription() {
return account.getDescription() + "+ validationOneRan";
}
public void validateStuff() {
System.out.println("Big validation!");
}
}
We can add more method like "validateOtherStuff()" to each decorator without any limitations.
public class ValidationTwo extends ValidationObjectDecorator {
private ValidationObject book;
public ValidationTwo(ValidationObject g) {
book = g;
}
#Override
public String getDescription() {
return book.getDescription() + " ran validationTwo";
}
public void validationMethod() {
System.out.println("Big Validation!");
}
}
package designpatterns.decorator;
public class Main {
public static void main(String[] args) {
ValidationObject g1 = new Account();
System.out.println(g1.getDescription());
ValidationOne g2 = new Account(g1);
System.out.println(g2.getDescription());
ValidationTwo g3 = new Book(g2);
System.out.println(g3.getDescription());
}
}
Perhaps you can create an interface which will define a function such as "validate()", create implementations of this interface and then iterate over the list and apply the validate function.
Example:
public interface validator{
public boolean validate();
}
class validateUserName{
public boolean validate(){
return true;
}
}
class validatePhone{
public boolean validate(){
return false;
}
}
List<Validator> list = new ArrayList<Validator>();
list.add(new validPhone());
list.add(new validUserName());
for(Validator v : list)
v.validate();

How can we write an annotation

I am very new to usage of annotation.
can anyone please tell me how can we declare an annotation and also call all the methods / variables that are declared with that annotation
am using java to implement this annotation
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
#Target(ElementType.FIELD)
public #interface isAnnotatedVariable {
String varName();
}
and used the annotation in
public class Example {
#isAnnotatedVariable(varName = "S")
public String var;
#isAnnotatedVariable(varName = "S")
public String var1;
}
and tried to get the variable names using
public class BuildStepClassDetector {
public static void main(String[] args) throws IOException {
BuildStepClassDetector build = new BuildStepClassDetector();
final Logger4J logger = new Logger4J(build.getClass().getName());
final HashMap<String, Class<?>> isAnnotatedVariables = new HashMap<String, Class<?>>();
final TypeReporter reporter = new TypeReporter() {
#SuppressWarnings("unchecked")
#Override
public Class<? extends Annotation>[] annotations() {
return new Class[] { isAnnotatedVariable.class };
}
#SuppressWarnings("unchecked")
#Override
public void reportTypeAnnotation(Class<? extends Annotation> arg0, String arg1) {
Class<? extends isAnnotatedVariable> isAnnotatedVariableClass;
try {
isAnnotatedVariableClass = (Class<? extends isAnnotatedVariable>) Class.forName(arg1);
isAnnotatedVariables.put(
isAnnotatedVariableClass.getAnnotation(isAnnotatedVariable.class).varName(),
isAnnotatedVariableClass);
} catch (ClassNotFoundException e) {
logger.getStackTraceString(e);
}
}
};
final AnnotationDetector cf = new AnnotationDetector(reporter);
cf.detect();
System.out.println(isAnnotatedVariables.keySet());
}
}
Here is a simple example for declaring annotation and retrieving a annotated field using Reflection.
package asif.hossain;
import java.lang.annotation.*;
import java.lang.reflect.Field;
/**
*
* Created by sadasidha on 21-Aug-14.
*/
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
#interface MyAnnotation {
public String value();
}
class TestClass
{
#MyAnnotation("This is a name field")
public String name;
}
public class Main {
public static void main(String ... args) throws IllegalAccessException {
TestClass testObject = new TestClass();
Field[] fields = testObject.getClass().getFields();
for (Field field : fields)
{
Annotation annotation = field.getAnnotation(MyAnnotation.class);
if(annotation instanceof MyAnnotation)
{
System.out.println(field.getName());
// get field value
String value = (String)field.get(testObject);
System.out.println("Field Value = "+ value);
//Set field value
field.set(testObject,"Your Name");
System.out.println(testObject.name);
}
}
}
}
You can follow this tutorial http://tutorials.jenkov.com/java-reflection/index.html to learn more about annotation and reflection.

Instantiating generic class and implementing generic interface

I have this class:
public DrawItem {
protected String getSeperator() {
return "";
}
.......
// some other methods
}
I've another class which extends DrawItem.
public DrawNumber extends DrawItem {
#Override
protected String getSeperator() {
return "-";
}
}
Now, in a generic class CombinationGenerator<E>, I'm trying to instantiate objects of DrawItem/DrawNumber. As instantiating a generic type is not possible in java (like new E(...)), I've created a Factory interface according to this answer.
public interface DrawItemFactory<E> {
E create(...);
}
Then in the CombinationGenerator<E> class,
public class CombinationGenerator<E> {
DrawItemFactory<E> factory;
public CombinationGenerator<E>(DrawItemFactory<E> factory) {
this.factory = factory;
}
public List<E> generate() {
......
list.add(factory.create(...));
......
}
}
And now the DrawNumber class implements DrawItemFactory<DrawItem> interface.
public DrawItem implements DrawItemFactory<DrawItem> {
protected String getSeperator() {
return "";
}
#Override
public DrawItem create(...) {
return new DrawItem(...);
}
.......
// some other methods
}
And I can create CombinationGenerator<DrawItem> class.
DrawItem drawItem = new DrawItem(...);
CombinationGenerator<DrawItem> generator = new CombinationGenerator<DrawItem>(drawItem);
List<DrawItem> combinations = generator.generate();
So far, everything is fine. But when I try to create a DrawNumber class like this,
public DrawNumber implements DrawItemFactory<DrawNumber> {
....
}
It gives me the following error:
The interface DrawItemFactory cannot be implemented more than once with different arguments: DrawItemFactory<DrawItem> and DrawItemFactory<DrawNumber>
I've tried this solution but I got the same error. Is there any other way to do this?
Instead of using all those factories you could do something like this:
public class CombinationGenerator<E> {
E instance;
public CombinationGenerator(Class<E> clazz) {
Constructor<?> con = clazz.getConstructor();
this.instance = (E) con.newInstance();
}
}
...
CombinationGenerator<DrawNumber> cg = new CombinationGenerator<DrawNumber>(DrawNumber.class);
According to #JB Nizet's comment, I've solved the problem by creating two separate factory classes like this:
public interface ItemFactory<E> {
E create(int[] values);
public static class DrawItemFactory implements ItemFactory<DrawItem> {
#Override
public DrawItem create(int[] values) {
return new DrawItem(values);
}
}
public static class DrawNumberFactory implements ItemFactory<DrawNumber> {
#Override
public DrawNumber create(int[] values) {
return new DrawNumber(values);
}
}
}
In the CombinationGenerator,
public class CombinationGenerator<E> {
ItemFactory<E> factory;
public CombinationGenerator<E>(ItemFactory<E> factory) {
this.factory = factory;
}
public List<E> generate() {
......
list.add(factory.create(...));
......
}
}
And instantiated CombinationGenerator like this:
DrawNumber drawNumber = new DrawNumber();
CombinationGenerator<DrawNumber> generator = new CombinationGenerator<DrawNumber>(new ItemFactory.DrawNumberFactory());
List<DrawNumber> combinations = generator.generate();

Categories

Resources