Can I force mapstruct to delegate a mapping method to another mapping method or a default (builtin) conversion?
I basically would like to access a custom mapping method of a uses MapperA inside the custom mapping method of the using MapperX. But I can't get a hold of the injected MapperA inside the custom mapping method of MapperX.
The same is true for builtin conversions. I want to make use of a builtin conversion of mapstruct inside a custom method. Like convert from Date to ZonedDateTime.
e.g.:
#Mapper(componentModel="cdi")
public interface MapperA {
A fromB(B b);
default Q fromR(R r) {
Q q = ..<do some stuff with r>..
return q;
}
}
#Mapper(componentModel="cdi"
uses = MapperA.class
)
public interface MapperX {
default X custom(Y y) {
Date someJavaUtilDate = customDateFromY(y);
//I dont want to code Date->ZonedDateTime myself
//I want mapstruct to do its builtin conversion, so call placeholder:
X.myZonedDateTime = builtinConversionPlaceholder(someJavaUtilDate)
R r = ..<do some stuff with y>..
X.q = usesMapperPlaceholder(r); // injected "uses MapperA" is not directly accessible here?
}
#org.mapstruct.Find_Me_A_Matching_Method_Builtin_Or_In_Uses_Mapper
// will not map properties of Date to ZonedDateTime
// but will use mapstruct builtin conversion code
ZonedDateTime builtinConversionPlaceholder(java.util.Date date);
#org.mapstruct.Find_Me_A_Matching_Method_Builtin_Or_In_Uses_Mapper
// will delegate to MapperA.fromR
Q usesMapperPlaceholder(R r);
}
No it is not possible to force MapStruct to use. build in conversion method.
What you can do is to create some wrapper objects that will be mapped between java.util.Date and ZonedDateTime, MapStruct will then map those using the built in mappings.
e.g.
#Mapper(componentModel="cdi")
public interface MapperA {
A fromB(B b);
default Q fromR(R r) {
Q q = ..<do some stuff with r>..
return q;
}
}
#Mapper(componentModel="cdi"
uses = MapperA.class
)
public abstract class MapperX {
#Inject
MapperA mapperA;
default X custom(Y y) {
Date someJavaUtilDate = customDateFromY(y);
X.myZonedDateTime = toZonedDateTime(someJavaUtilDate).getValue();
R r = ..<do some stuff with y>..
X.q = mapperA.fromR(r);
}
Wrapper<ZonedDateTime> toZonedDateTime(Wrapper<java.util.Date> date);
static class Wrapper<T> {
private T value;
//getters and setters
}
}
I am currently writing a wrapper around socket.io. Comming from a very object-oriented background, I want to implement the concept of Models in my framework/wrapper.
If you happen to know socket.io you might know that you get the data that is associated with an event as a parameter, now I have implemented a custom routing system where the handler of the route gets the data in an express.js like request object.
The idea is to have model classes that look something like this:
class XRequestModel
#v.String({ message: 'The username must be a string!' })
public userName: string;
}
And the route event might look something like this:
#RouteConfig({ route: '/something', model: XRequestModel })
class XEvent extends Route {
public on(req: Request<XRequestModel>, res: Response) {
// Handle Event
}
}
And to complete the example here is how the request object might look like:
class Request<T> {
public data: T;
}
Now generics in typescript are very limited since the type information is removed after compilation, I can not use the generic Request parameter ( which is the type of the model ) to get metadata from the model - Metadata, in this case, is the validation decorator. To overcome this issue I give a reference of the Model class to the RouteConfig of the RouteEvent, which is internally used and would allow me to create instances of the model, get the properties and so on...
The idea here is to give the handler of a route, a request object with pre-validated, typesafe data.
The thing holding me back from this, is the fact that unused properties, get removed after compilation by typescript, So I cannot get the metadata of the model. Initializing the class-property would solve this:
class XRequestModel
#v.String({ message: 'The username must be a string!' })
public userName: string = '';
}
But I think this makes for some very verbose syntax, and I dont want to force the user of this wrapper to init all the model properties.
An implementation side-note:
The user of the framework has to register the classes to a 'main' class and from there I can get the Route-class via decorator reflection.
When I try to get the properties of the model without initialized properties - First model example.
// Here the route.config.model refers to the model from the RouteConfig
Object.getOwnPropertyNames(new route.config.model());
>>> []
Here is what I get with initialized properties:
Object.getOwnPropertyNames(new route.config.model());
>>> [ 'userName' ]
Here a link to the GitHub repository: https://github.com/FetzenRndy/SRocket
Note that models are not implemented in this repo yet.
Basically, my question is: How can I get the properties of a class that has uninitialized properties after compilation.
The problem is that if no initialization happens, no code is emitted for the fields, so at runtime the field does not exist on the object until a value is assigned to it.
The simplest solution would be to initialize all fields even if you do so with just null :
class XRequestModel {
public userName: string = null;
public name: string = null;
}
var keys = Object.getOwnPropertyNames(new XRequestModel())
console.log(keys); // [ 'userName', 'name' ]
If this is not a workable solution for you, you can create a decorator that adds to a static field on the class and the walk up the prototype chain to get all fields:
function Prop(): PropertyDecorator {
return (target: Object, propertyKey: string): void => {
let props: string[]
if (target.hasOwnProperty("__props__")) {
props = (target as any)["__props__"];
} else {
props = (target as any)["__props__"] = [];
}
props.push(propertyKey);
};
}
class XRequestModelBase {
#Prop()
public baseName: string;
}
class XRequestModel extends XRequestModelBase {
#Prop()
public userName: string;
#Prop()
public name: string;
}
function getAllProps(cls: new (...args: any[]) => any) : string[] {
let result: string[] = [];
let prototype = cls.prototype;
while(prototype != null) {
let props: string[] = prototype["__props__"];
if(props){
result.push(...props);
}
prototype = Object.getPrototypeOf(prototype);
}
return result;
}
var keys = getAllProps(XRequestModel);
console.log(keys);
I've used the first two videos in this series to learn about some basic OOP concepts.
Lately, I primarily write in Node, so I'm working with prototypical inheritance on the front-end and back-end. However, these tutorials showcase OOP concepts with Java. Java is a strictly-typed language which utilizes classical inheritance.
This question pertains to both classical and prototypical inheritance, but in different ways.
This problem is a little bit difficult to put into words, so I'll use an example:
I've created a super-class called animal. I then create two sub-classes of animal: horse and donkey. Now my program requires a hybrid of the two sub-classes. Creating a mule actually seems to be a little tricky.
At first the answer seemed obvious; create a stand-alone mule sub-class. But that kind of defeats the purpose of OOP. Creating a new sub-class when I already have the traits is a violation of the DRY principle.
To confirm that this is an appropriate way to create my mule I asked myself two questions:
1) Is a mule a horse?
2) Is a mule a donkey?
The answer seemed to be a resounding kind of that leans towards a yes.
I'm completely lost as to how this would be accomplished with classical inheritance. I could not come up with what I considered a "good" solution with interfaces or abstract classes.
In a language which use prototypical inheritance like JavaScript, I might "selectively breed" a mule by pulling down only the methods and instance variables that applied to a mule. However, this seems to be rather close to creating a brand-new sub-class.
What is the "correct" way to handle this problem in both classical and prototypical inheritance?
The concept you are looking for is traits (you actually mentioned it). I will use a different example, that I find more appropriate:
trait Engine {
public function startEngine() {
echo 'Vrooom';
}
}
trait Saddle {
public function rideOnSaddle() {
echo 'I feel the wind';
}
}
interface Vehicle {
public function go();
}
class Car extends Vehicle {
use Engine;
public function go() {
echo $this->startEngine();
}
}
class Bike extends Vehicle {
use Saddle;
public function go() {
echo $this->rideOnSaddle();
}
}
class Motorcycle extends Vehicle {
use Engine;
use Saddle;
public function go() {
echo $this->startEngine();
echo $this->rideOnSaddle();
}
}
Further reading: Traits in PHP, Traits in Javascript.
At first the answer seemed obvious; create a stand-alone mule sub-class.
But that kind of defeats the purpose of OOP. Creating a new sub-class
when I already have the traits is a violation of the DRY principle.
Decomposition might help reaching the DRY goal.
Every behavior/role that not obviously should be inherited, might be considered of being implemented as mixin or trait.
Thus theirs code reuse at different places at class level is much easier and more elegant now via composition.
As for JavaScript, there is only delegation. Inheritance at one hand is supported by an implicit delegation automatism
via the prototype chain, whereas composition gets achieved by delegating functionality explicitly via call or apply.
This makes things much easier since one only needs to deal with objects/instances and methods/function-objects. The class/inheritance
part in JavaScript is covered by either constructor functions and every constructor function's prototype or by (blueprint-)objects that
are passed as prototypes to Object.create. Factories will be useful in providing an API and hiding the preferred implementation of one
of the above mentioned approaches.
Nevertheless the core principles remain untouched with both of them ... dealing with a) objects and function-objects
with b) inheritance and with c) composition.
The following provided example therefore chooses just ECMAScript-3 features and constructor functions. From there it can
be easily transferred(/transpiled) to either class syntax or Object.create.
The OP's example is well chosen, for a mule is neither a horse nor a donkey. It still does belong to the genus Equus but features
its very own chromosome pairs that are distinct from the one of horses or donkeys. Yet it features behavior and visible markers
of both of them. Inheritance therefore, if at all, is achieved via the Equus. Other behavior and appearance that is either specific
or generic to each of both species just will be mixed into a mule.
Function based mixins / traits / talents in JavaScript always get applied to objects/instances, thus even behavior that will be inherited
via the prototype chain, can be collected into such functionality that again can be applied to a prototypal object if necessary/appropriate.
The following example makes use of this technique and also does comment on it in order to demonstrate DRY-ness and code reuse
at this 2 delegation levels of JavaScript.
var
INITIAL_STATES_CONFIG = {
equus: {
specifics: {
type: "equus"
}/*,
generics: {
}*/
},
horse: {
specifics: {
type: "horse"
}/*,
generics: {
}*/
},
donkey: {
specifics: {
type: "donkey"
}/*,
generics: {
}*/
},
mule: {
specifics: {
type: "mule"
}/*,
generics: {
}*/
}
};
function withToeltGait() { // function based mixin/trait/talent.
this.toelt = function () {
return "... tölt ...";
};
return this;
}
function withEquusGenerics(/* state */) { // function based mixin/trait/talent composite.
var
equus = this;
// implementation of equus generics.
equus.walk = function () {
return "... walk ...";
};
equus.trot = function () {
return "... trot ...";
};
equus.gallop = function () {
return "... gallop ...";
};
withToeltGait.call(equus); // composition: use/apply specific equus trait.
return equus;
}
function withEquusSpecifics(state ) { // function based mixin/trait/talent.
var
equus = this;
// implementation of equus specifics.
equus.valueOf = function () {
return Object.assign({}, state);
};
equus.toString = function () {
return JSON.stringify(state);
};
return equus;
}
function Equus(state) { // constructor, kept generic via mixin/trait/talent composition.
state = ((typeof state === 'object') && state) || {};
var
equus = this;
withEquusSpecifics.call(equus, state); // composition: use/apply specific equus trait.
return equus;
}
// equus inheritance via trait based generic equus composite object.
Equus.prototype = withEquusGenerics.call(new Equus/*, state */);
console.log("Equus.prototype.valueOf() : ", Equus.prototype.valueOf());
console.log("Equus.prototype.toString() : ", Equus.prototype.toString());
console.log("Equus.prototype.walk() : ", Equus.prototype.walk());
console.log("Equus.prototype.trot() : ", Equus.prototype.trot());
console.log("Equus.prototype.toelt() : ", Equus.prototype.toelt());
console.log("Equus.prototype.gallop() : ", Equus.prototype.gallop());
console.log("\n");
var equus = new Equus(INITIAL_STATES_CONFIG.equus.specifics);
console.log("equus.valueOf() : ", equus.valueOf());
console.log("equus.toString() : ", equus.toString());
console.log("equus instanceof Equus ? ", (equus instanceof Equus));
console.log("+++ +++ +++\n\n");
function withHorseGenerics(/* state */) { // function based mixin/trait/talent.
/*
implementation of horse generics.
*/
var
horse = this;
// almost all of today's horse breeds lost theirs genetic tölt predisposition.
horse.toelt = function () {};
horse.alwaysAlertedAndFleeQuickly = function () {
return "... always alerted and flee quickly ...";
};
return horse;
}
function withHorseSpecifics(/* state */) { // function based mixin/trait/talent.
/*
implementation of horse specifics.
*/
return this;
}
function Horse(state) { // constructor, kept generic via mixin/trait/talent composition.
state = ((typeof state === 'object') && state) || {};
var
horse = this;
Equus.call(horse, state); // - fulfilling proper equus composition.
withHorseSpecifics.call(horse/*, state */); // - composition: use/apply specific horse trait.
return horse;
}
// equus inheritance together with generic horse trait composition.
Horse.prototype = withHorseGenerics.call(new Equus/*, state */);
var horse = new Horse(INITIAL_STATES_CONFIG.horse.specifics);
console.log("horse.valueOf() : ", horse.valueOf());
console.log("horse.toString() : ", horse.toString());
console.log("horse instanceof Horse ? ", (horse instanceof Horse));
console.log("horse instanceof Equus ? ", (horse instanceof Equus));
console.log("horse.walk() : ", horse.walk());
console.log("horse.trot() : ", horse.trot());
console.log("horse.toelt() : ", horse.toelt());
console.log("horse.gallop() : ", horse.gallop());
console.log("horse.alwaysAlertedAndFleeQuickly() : ",
(horse.alwaysAlertedAndFleeQuickly && horse.alwaysAlertedAndFleeQuickly())
);
console.log("horse.beAttentiveCalculateAndRatherFight() : ",
(horse.beAttentiveCalculateAndRatherFight && horse.beAttentiveCalculateAndRatherFight())
);
console.log("\n");
var toeltingHorse = new Horse(INITIAL_STATES_CONFIG.horse.specifics);
withToeltGait.call(toeltingHorse);
console.log("toeltingHorse.valueOf() : ", toeltingHorse.valueOf());
console.log("toeltingHorse instanceof Horse ? ", (toeltingHorse instanceof Horse));
console.log("toeltingHorse instanceof Equus ? ", (toeltingHorse instanceof Equus));
console.log("toeltingHorse.toelt() : ", toeltingHorse.toelt());
console.log("+++ +++ +++\n\n");
function withDonkeyGenerics(/* state */) { // function based mixin/trait/talent.
/*
implementation of donkey generics.
*/
var
donkey = this;
// donkey breeds, as far as I know, still have the genetic
// predisposition for tölt, but they need to get trained.
//
// donkey.toelt = function () {};
donkey.beAttentiveCalculateAndRatherFight = function () {
return "... be attentive, calculate and rather fight ...";
};
return donkey;
}
function withDonkeySpecifics(/* state */) { // function based mixin/trait/talent.
/*
implementation of donkey specifics.
*/
return this;
}
function Donkey(state) { // constructor, kept generic via mixin/trait/talent composition.
state = ((typeof state === 'object') && state) || {};
var
donkey = this;
Equus.call(donkey, state); // - fulfilling proper equus composition.
withDonkeySpecifics.call(donkey/*, state */); // - composition: use/apply specific donkey trait.
return donkey;
}
// equus inheritance together with generic donkey trait composition.
Donkey.prototype = withDonkeyGenerics.call(new Equus/*, state */);
var donkey = new Donkey(INITIAL_STATES_CONFIG.donkey.specifics);
console.log("donkey.valueOf() : ", donkey.valueOf());
console.log("donkey.toString() : ", donkey.toString());
console.log("donkey instanceof Donkey ? ", (donkey instanceof Donkey));
console.log("donkey instanceof Equus ? ", (donkey instanceof Equus));
console.log("donkey.walk() : ", donkey.walk());
console.log("donkey.trot() : ", donkey.trot());
console.log("donkey.toelt() : ", donkey.toelt());
console.log("donkey.gallop() : ", donkey.gallop());
console.log("donkey.alwaysAlertedAndFleeQuickly() : ",
(donkey.alwaysAlertedAndFleeQuickly && donkey.alwaysAlertedAndFleeQuickly())
);
console.log("donkey.beAttentiveCalculateAndRatherFight() : ",
(donkey.beAttentiveCalculateAndRatherFight && donkey.beAttentiveCalculateAndRatherFight())
);
console.log("+++ +++ +++\n\n");
function withMuleGenerics(/* state */) { // function based mixin/trait/talent composite.
/*
implementation of mule generics.
*/
var
mule = this;
withDonkeyGenerics.call(mule/*, state */); // composition: use/apply generic donkey trait.
/*
add or delete mule generic properties afterwards.
*/
withHorseGenerics.call(mule/*, state */); // composition: use/apply generic horse trait.
/*
add or delete mule generic properties afterwards.
*/
// a mules genetic predisposition for tölt is inherited by its mother horse.
// therefore via calling `withHorseGenerics` this trait gets disabled too by default.
// when facing danger a mule behaves like a donkey; it rather will fight than flee.
mule.alwaysAlertedAndFleeQuickly = function () {};
return mule;
}
function withMuleSpecifics(/* state */) { // function based mixin/trait/talent composite.
/*
implementation of mule specifics.
*/
var
mule = this;
withDonkeySpecifics.call(mule/*, state */); // composition: use/apply specific donkey trait.
/*
add or delete mule specific properties afterwards.
*/
withHorseSpecifics.call(mule/*, state */); // composition: use/apply specific horse trait.
/*
add or delete mule specifics properties afterwards.
*/
return mule;
}
function Mule(state) { // constructor, kept generic via mixin/trait/talent composition.
state = ((typeof state === 'object') && state) || {};
var
mule = this;
Equus.call(mule, state); // - fulfilling proper equus composition.
withMuleSpecifics.call(mule/*, state */); // - composition: use/apply specific mule trait.
return mule;
}
// equus inheritance together with generic mule trait composition.
Mule.prototype = withMuleGenerics.call(new Equus/*, state */);
var mule = new Mule(INITIAL_STATES_CONFIG.mule.specifics);
console.log("mule.valueOf() : ", mule.valueOf());
console.log("mule.toString() : ", mule.toString());
console.log("mule instanceof Mule ? ", (mule instanceof Mule));
console.log("mule instanceof Equus ? ", (mule instanceof Equus));
console.log("mule instanceof Donkey ? ", (mule instanceof Donkey));
console.log("mule instanceof Horse ? ", (mule instanceof Horse));
console.log("mule.walk() : ", mule.walk());
console.log("mule.trot() : ", mule.trot());
console.log("mule.toelt() : ", mule.toelt());
console.log("mule.gallop() : ", mule.gallop());
console.log("mule.alwaysAlertedAndFleeQuickly() : ",
(mule.alwaysAlertedAndFleeQuickly && mule.alwaysAlertedAndFleeQuickly())
);
console.log("mule.beAttentiveCalculateAndRatherFight() : ",
(mule.beAttentiveCalculateAndRatherFight && mule.beAttentiveCalculateAndRatherFight())
);
console.log("\n");
var toeltingMule = new Mule(INITIAL_STATES_CONFIG.mule.specifics);
withToeltGait.call(toeltingMule);
console.log("toeltingMule.valueOf() : ", toeltingMule.valueOf());
console.log("toeltingMule instanceof Mule ? ", (toeltingMule instanceof Mule));
console.log("toeltingMule instanceof Equus ? ", (toeltingMule instanceof Equus));
console.log("toeltingMule.toelt() : ", toeltingMule.toelt());
console.log("+++ +++ +++\n\n");
side note - recommended resources on functions based Mixins / Traits / Talents in JavaScript
A fresh look at JavaScript Mixins by Angus Croll from May 2011
The many talents of JavaScript for generalizing Role Oriented Programming approaches like Traits and Mixins from April 2014.
Additionally I do recommend reading some of the listed answers of mine given on SO, that are related to this topic too.
Traits in javascript
How to use mixins properly in Javascript
ES 6 Classes - Mixins
I have a case where I want to have just a get in the interface, no set. Is there a way to do that?
If not, we can implement a set and throw an exception if it is called. But it's cleaner if we can have just a get.
At present I have:
export interface IElement {
type : TYPE;
}
export class Element implements IElement {
public get type () : TYPE {
return TYPE.UNDEFINED;
}
public set type (type : TYPE) {
this.type = type;
}
}
I would like to have my interface & class be:
export class Element implements IElement {
public get type () : TYPE {
return TYPE.UNDEFINED;
}
}
TypeScript interfaces cannot currently define a property as read-only. If it's important to prevent, you'll need to throw an exception/error at runtime to prevent sets within the setter for the property.
The compiler doesn't require that you implement the get and a set though. You can just implement the get for example. However, at runtime, it won't be caught.
I would like to have an embedded document referred to by a map (as in 'class A' below). The environment is Grails + GORM + MongoDB.
is that possible, and if yes, how?
class A { // fails with IllegalArgumentException occurred when processing request: can't serialize class X in line 234 of org.bson.BasicBSONEncoder
static mapWith = "mongo"
Map<String, X> map = new HashMap<String, X>()
}
class B { // works
static mapWith = "mongo"
List<X> list = new ArrayList<X>()
}
class C { // works with primitive type values
static mapWith = "mongo"
Map<String, String> map = new HashMap<String, String>()
}
class X {
String data
public X(String data) {
this.data = data
}
}
The embedding works perfectly,as Art Hanzel advised.
However your problem comes from the fact that you try and use List genericity as a sort of constraint :
Map<String, X>
The problem is that Grails couldn't cope well with this syntax, first because Groovy doesn't support genericity.
However, the MongoDB plugin offers a very powerful functionality that lets you define custom type as Domain Class Properties : see here.
In your case you could have
class A {
static mapWith = "mongo"
MyClass map = new MyClass()
}
Then in your src/java for example you could for example implement a
class MyClass extends HashMap<String,X> { }
Then, of course, you have to define a special AbstractMappingAwareCustomTypeMarshaller to specify how to read and write the property in the DB.
An additional step could also be to add a custom validator to class A to check the validity of data...
The MongoDB Grails plugin documentation describes how to make embedded documents:
class Foo {
Address address
List otherAddresses
static embedded = ['address', 'otherAddresses']
}
Off the top of my head, you should be able to access these via the object graph. I don't see any reason why you shouldn't.
myFoo.address.myAddressProperty...