Skip to content

My Batis Unable to create objects by constructor with collection as argument #1382

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
patan12 opened this issue Oct 30, 2018 · 3 comments
Closed

Comments

@patan12
Copy link

patan12 commented Oct 30, 2018

MyBatis, Unable to create objects by constructor with collection as argument

I have immuatble classes, I am struct with the below error while instantiating objects.

Tables

      CREATE TABLE employee (
        id varchar NOT NULL,
        "name" varchar NOT NULL
      )
    
      CREATE TABLE muzimil.address (
        id varchar NOT NULL,
        street varchar NOT NULL,
        city varchar NOT NULL,
        emp_id varchar NULL
      )

Java Classes

    @Data
    @Builder
    @AllArgsConstructor
    public class Employee {

      private final String id;
      private final String name;
      private final List<Address> addresses;


    }

    @Data
    @Builder
    @AllArgsConstructor
    public class Address {

      private final String id;
      private final String street;
      private final String city;
      private final String employeeId;

    }

MyBatis: Mapper

  <select id="getById" resultMap="employeeResultMap">
    select
    emp.id as employeeId,
    emp.name as name,
    aa.id as addressId,
    aa.street as street,
    aa.city as city
    from employee emp
    join address aa
    on emp.id=aa.emp_id
    where emp.id = #{id};
  </select>

  <resultMap id="employeeResultMap" type="Employee">
    <constructor>
      <idArg column="employeeId" javaType="String" name="id"/>
      <arg column="name" javaType="String" name="name"/>
      <arg resultMap="addressMap" name="addresses"/>
    </constructor>
  </resultMap>


  <resultMap id="addressMap" type="java.util.List">
    <association property="addresses" javaType="Address">
    <collection property="address" javaType="java.util.ArrayList" ofType="Address">
      <constructor>
        <idArg column="addressId" javaType="String" name="id"/>
        <arg column="street" javaType="String" name="street"/>
        <arg column="city" javaType="String" name="city"/>
        <arg column="employeeId" javaType="String" name="employeeId"/>
      </constructor>
    </collection>
    </association>

  </resultMap>

Error:

Caused by: org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: java.lang.UnsupportedOperationException
### The error may exist in file [/Users/mchavak/Documents/muzimil/POC/postgres/ibatis/build/resources/main/mybatis/mapper/BrandMapper.xml]
### The error may involve com.muzimi.postgres.ibatis.EmployeeMapper.getById
### The error occurred while handling results
### SQL: select     emp.id as employeeId,     emp.name as name,     aa.id as addressId,     aa.street as street,     aa.city as city     from employee emp     join address aa     on emp.id=aa.emp_id     where emp.id = ?;
### Cause: java.lang.UnsupportedOperationException
@harawata
Copy link
Member

This may be a duplicate of #101 .
It's a known limitation due to technical difficulties.

@patan12
Copy link
Author

patan12 commented Oct 31, 2018

@harawata Thanks. is there any work around to achieve this immutable class

@harawata
Copy link
Member

There may be several approaches.
I'm not sure if it meets your requirement, but the easiest I can think of is to create a mutable version of Employee class and convert it to immutable in your service layer or in ResultHandler.

  <resultMap type="test.EmployeeMutable" id="employeeMap">
    <id property="id" column="employeeId" />
    <result property="name" column="name" />
    <collection property="addresses" resultMap="addressMap" />
  </resultMap>

  <resultMap type="test.Address" id="addressMap">
    <constructor>
      <idArg column="addressId" javaType="int" />
      <arg column="street" javaType="string" />
      <arg column="city" javaType="string" />
      <arg column="employeeId" javaType="int" />
    </constructor>
  </resultMap>

With this approach, Address is still immutable, so the conversion is relatively easy.

new Employee(
  mutable.getId(),
  mutable.getName(),
  Collections.unmodifiableList(mutable.getAddresses()));

Closing as a duplicate of #101 .

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

No branches or pull requests

2 participants