I am attempting to use Mapstruct to map a DTO from a ResultSet.
This is not directly possible without using expresson in the @Mapping
annotation like this:
@Mapping(target="name", expression = "java(rs.getString("propName"))")
@Mapping(target="value", expression = "java(rs.getString("propValue"))")
NameValuePair map(ResultSet rs) throws SQLException;
This is an ugly solution. However, the Mapstruct developers have decided they will not provide direct support for ResultSet mapping (source).
Is it possible to use Mapstruct @Context
and qualifiedByName
to do something like this (this doesn’t work because ResultSet
doesn’t have a field named “source”)?
// doesn't work, source doesn't exist on ResultSet
@Mapping(target="name", source="name", qualifiedByName = "stringValue")
@Mapping(target="value", source="value", qualifiedByName = "stringValue")
NameValuePair map(String source, @Context ResultSet rs);
@Named("stringValue")
default String stringValue(String source, @Context ResultSet resultSet) {
try {
String result = resultSet.getString(source);
return result;
} catch (SQLException e) {
return null; // no, I'm not really going to return null
}
}
I’ve looked for an easy explanation in the Mapstruct reference guide, but nothing is jumping out at me.
Can anyone help?
EDIT 2: Implementation of NameValuePair
@Data
@NoArgsConstructor
@AllArgsConstructor
public class NameValuePair {
private String name;
private String value;
// convenience constructor for going from a Map<String, Object> but
// you're sure value is a string
public NameValuePair(Object name, Object value) {
this((String) name, (String) value);
}
}
EDIT: To you anonymous people voting to close my question, why don’t you tell me what’s wrong with it?
Your target has to be a property in your output object, in your case, it is NameValuePair
. Meaning to say, both “name” and “value” are String properties in this class.
Can you provide a snippet of that class? Additionally, can you also provide a snippet of your ResultSet.getString(String source)
method?
Edit: You mapped your source wrongly. You should map it as so:
@Mapping(target="name", source="source", qualifiedByName = "stringValue")
@Mapping(target="value", source="source", qualifiedByName = "stringValue")
NameValuePair map(String source, @Context ResultSet rs);
To further illustrate this mapping, imagine:
@Getter
public class Source {
private String name;
}
A Mapstruct mapper for above class would then be:
@Mapping(target="name", source="source.name", qualifiedByName = "stringValue")
@Mapping(target="value", source="source.name", qualifiedByName = "stringValue")
NameValuePair map(Source source, @Context ResultSet rs);
Or alternatively:
@Mapping(target="name", source="source", qualifiedByName = "qualifySource")
@Mapping(target="value", source="source", qualifiedByName = "qualifySource")
NameValuePair map(Source source, @Context ResultSet rs);
with its @Named
method:
@Named("qualifySource")
default String stringValue(Source source, @Context ResultSet resultSet) {
try {
String result = resultSet.getString(source.getName());
return result;
} catch (Exception e) {
return "";
}
}
3