Can I configure myBatis to create an instance of a class using the Builder Pattern?
Asked Answered
A

1

10

I have a (Java) class with many instance fields (many of which are optional). I would like all fields (thus class) to be immutable. So, I would like to use the Builder Pattern for constructing instances of the class.

Can I configure myBatis to create an instance of a class using the Builder Pattern? I know that I could have myBatis return a map and use that map to build in the instance in my code. However, I'm looking for a way to configure this mapping (or use some convention) similar to how can create instance via use of Java Beans and constructors.

Edit (to include an example)

Here's an example:

package com.example.model;

// domain model class with builder
public final class CarFacts {

    private final double price;
    private final double numDoors;
    private final String make;
    private final String model;
    private final String previousOwner;
    private final String description;

    public static class Builder {
        // required params
        private final double price;
        private final String make;
        private final String model;

        // optional params
        private final String previousOwner;
        private final String description;
        private final double numDoors;

        public Builder(double price, String make, String model) {
            this.price = price;
            this.make = make;
            this.model = model;
        }

        public Builder previousOwner(String previousOwner) {
            this.previousOwner = previousOwner;
            return this;
        }
        // other methods for optional param

        public CarFacts build() {
            return new CarFacts(this);
        }
    }

    private CarFacts(Builder builder) {
        this.price = builder.price;
        //etc.
    }
}

Then, I have a mapper as:

<!-- this doesn't work but I think h3adache suggest that I could have the resultType
be com.example.model.CarFacts.Builder and use the Builder constructor. But I'm not sure how
I would call the methods (such previousOwner(String)) to populate optional params -->

<mapper namespace="com.example.persistence.CarFactsMapper">
  <select id="selectCarFacts" resultType="com.example.model.CarFacts">
    select *
    from CarFacts
  </select>
    
</mapper>

Finally, I have the mapper interface:

package com.example.persistence.CarFactsMapper;

public interface CarFactsMapper {
    List<CarFacts> selectCarFacts();
}

I would also like to be able to create instances using a static factory method via myBatis. For example:

public final class Person {

    private final String lastName;
    private final String firstName;

    private Person(String lastName, String firstName) {
        this.lastName = lastName;
        this.firstName = firstName;
    }

    public Person newInstance(String lastName, String firstName) {
        return new Person(lastName, firstName);
    }
}

Specifically, how can I have myBatis call newInstance(String, String)?

Ambience answered 28/3, 2013 at 16:8 Comment(1)
From my experience, you cannot map to final/immutable fields into your pojos/beans. Also have a look at mybatis.org/mybatis-3/sqlmap-xml.html#Result_Maps further read on constructor injection.Elmira
H
-2

You need not use a builder or static factory method. Yes if you're trying to maintain immutability these patterns certainly help since mutations can occur, shall we say 'between instances' e.g. as the builder is being mutated before its call to build() (to create a new immutable instance).

Immutability though, is independent of how a given instance is constructed. It doesn't get us anywhere to write builders and static factory methods for a class that is mutable. At the point of construction all objects are not yet mutated and so what really matters is what can happen next (after the builders and factories have left).

All you need to do is focus on the class itself and think ok is this class Immutable. The regular myBatis mapping should be fine - save yourself the time of writing a builder.

So - is your class immutable, well yes it is since all your fields are final and either primitive types or String (which is immutable in Java!). If you had other non-primitive fields then you'd want them to be final (technically you don't need to write final but it is recommended, so long as the field is never actually reassigned) and you'd want their class to follow a recursion of these rules all the way down.

I hope this helps, the point I want to get across is that the builder pattern and factory methods are good for managing construction but they don't give you the immutability for free and you always need to write a constructor.

Holograph answered 6/4, 2013 at 7:17 Comment(1)
This doesn't answer the question.Magree

© 2022 - 2024 — McMap. All rights reserved.