• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mybatis / cdi / #1015

28 May 2024 08:39PM CUT coverage: 93.033%. Remained the same
#1015

Pull #469

github

web-flow
Update dependency org.mybatis:mybatis-parent to v44
Pull Request #469: Update dependency org.mybatis:mybatis-parent to v44

79 of 100 branches covered (79.0%)

227 of 244 relevant lines covered (93.03%)

0.93 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.22
/src/main/java/org/mybatis/cdi/MybatisExtension.java
1
/*
2
 *    Copyright 2013-2023 the original author or authors.
3
 *
4
 *    Licensed under the Apache License, Version 2.0 (the "License");
5
 *    you may not use this file except in compliance with the License.
6
 *    You may obtain a copy of the License at
7
 *
8
 *       https://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 *    Unless required by applicable law or agreed to in writing, software
11
 *    distributed under the License is distributed on an "AS IS" BASIS,
12
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 *    See the License for the specific language governing permissions and
14
 *    limitations under the License.
15
 */
16
package org.mybatis.cdi;
17

18
import jakarta.enterprise.event.Observes;
19
import jakarta.enterprise.inject.spi.AfterBeanDiscovery;
20
import jakarta.enterprise.inject.spi.AnnotatedMember;
21
import jakarta.enterprise.inject.spi.AnnotatedType;
22
import jakarta.enterprise.inject.spi.Extension;
23
import jakarta.enterprise.inject.spi.InjectionPoint;
24
import jakarta.enterprise.inject.spi.InjectionTarget;
25
import jakarta.enterprise.inject.spi.ProcessAnnotatedType;
26
import jakarta.enterprise.inject.spi.ProcessInjectionTarget;
27
import jakarta.enterprise.inject.spi.ProcessProducer;
28
import jakarta.enterprise.inject.spi.WithAnnotations;
29
import jakarta.inject.Named;
30
import jakarta.inject.Qualifier;
31

32
import java.lang.annotation.Annotation;
33
import java.lang.reflect.Type;
34
import java.util.ArrayList;
35
import java.util.Collections;
36
import java.util.HashSet;
37
import java.util.List;
38
import java.util.Set;
39

40
import org.apache.ibatis.session.SqlSession;
41
import org.apache.ibatis.session.SqlSessionFactory;
42
import org.slf4j.Logger;
43
import org.slf4j.LoggerFactory;
44

45
/**
46
 * MyBatis CDI extension.
47
 *
48
 * @author Frank D. Martinez [mnesarco]
49
 */
50
public class MybatisExtension implements Extension {
1✔
51

52
  private static final Logger LOGGER = LoggerFactory.getLogger(MybatisExtension.class.getName());
1✔
53

54
  private final Set<BeanKey> sessionProducers = new HashSet<>();
1✔
55

56
  private final Set<Type> mapperTypes = new HashSet<>();
1✔
57

58
  private final Set<InjectionPoint> injectionPoints = new HashSet<>();
1✔
59

60
  /**
61
   * Collect types of all mappers annotated with Mapper.
62
   *
63
   * @param <T>
64
   *          the generic type
65
   * @param pat
66
   *          the pat
67
   */
68
  protected <T> void processAnnotatedType(
69
      @Observes @WithAnnotations({ Mapper.class }) final ProcessAnnotatedType<T> pat) {
70
    final AnnotatedType<T> at = pat.getAnnotatedType();
1✔
71
    if (at.isAnnotationPresent(Mapper.class)) {
1!
72
      LOGGER.info("MyBatis CDI Module - Found class with @Mapper-annotation: {}", at.getJavaClass().getSimpleName());
1✔
73
      this.mapperTypes.add(at.getBaseType());
1✔
74
    }
75
  }
1✔
76

77
  /**
78
   * Collect all SqlSessionFactory producers annotated with SessionFactoryProvider.
79
   *
80
   * @param <T>
81
   *          the generic type
82
   * @param <X>
83
   *          the generic type
84
   * @param pp
85
   *          the pp
86
   */
87
  @SuppressWarnings("unchecked")
88
  protected <T, X> void processProducer(@Observes final ProcessProducer<T, X> pp) {
89
    final AnnotatedMember<T> am = pp.getAnnotatedMember();
1✔
90
    final boolean isAnnotated = am.isAnnotationPresent(SessionFactoryProvider.class);
1✔
91
    final boolean isSqlSessionFactory = am.getBaseType().equals(SqlSessionFactory.class);
1✔
92
    final String logData = String.join(".", am.getJavaMember().getDeclaringClass().getSimpleName(),
1✔
93
        am.getJavaMember().getName());
1✔
94
    if (isAnnotated) {
1✔
95
      if (isSqlSessionFactory) {
1!
96
        LOGGER.info("MyBatis CDI Module - SqlSessionFactory producer {}", logData);
1✔
97
        this.sessionProducers.add(new BeanKey((Class<Type>) (Type) SqlSession.class, am.getAnnotations()));
1✔
98
      } else {
99
        LOGGER.error("MyBatis CDI Module - Invalid return type (Must be SqlSessionFactory): {}", logData);
×
100
        pp.addDefinitionError(new MybatisCdiConfigurationException(
×
101
            String.format("SessionFactoryProvider producers must return SqlSessionFactory (%s)", logData)));
×
102
      }
103
    } else if (isSqlSessionFactory) {
1!
104
      LOGGER.warn(
×
105
          "MyBatis CDI Module - Ignored SqlSessionFactory producer because it is not annotated with @SessionFactoryProvider: {}",
106
          logData);
107
    }
108
  }
1✔
109

110
  /**
111
   * Collect all targets to match Mappers and Session providers dependency.
112
   *
113
   * @param <X>
114
   *          the generic type
115
   * @param event
116
   *          the event
117
   */
118
  protected <X> void processInjectionTarget(@Observes ProcessInjectionTarget<X> event) {
119
    final InjectionTarget<X> it = event.getInjectionTarget();
1✔
120
    this.injectionPoints.addAll(it.getInjectionPoints());
1✔
121
  }
1✔
122

123
  /**
124
   * Register all mybatis injectable beans.
125
   *
126
   * @param abd
127
   *          the abd
128
   */
129
  @SuppressWarnings("unchecked")
130
  protected void afterBeanDiscovery(@Observes final AfterBeanDiscovery abd) {
131
    LOGGER.info("MyBatis CDI Module - Activated");
1✔
132

133
    Set<BeanKey> mappers = new HashSet<>();
1✔
134
    Set<BeanKey> sessionTargets = new HashSet<>();
1✔
135

136
    for (InjectionPoint ip : injectionPoints) {
1✔
137
      if (this.mapperTypes.contains(ip.getAnnotated().getBaseType())) {
1✔
138
        LOGGER.info("MyBatis CDI Module - Found a bean, which needs a Mapper {}", ip.getAnnotated().getBaseType());
1✔
139
        mappers.add(new BeanKey((Class<Type>) ip.getAnnotated().getBaseType(), ip.getAnnotated().getAnnotations()));
1✔
140
      } else if (SqlSession.class.equals(ip.getAnnotated().getBaseType())) {
1✔
141
        sessionTargets
1✔
142
            .add(new BeanKey((Class<Type>) ip.getAnnotated().getBaseType(), ip.getAnnotated().getAnnotations()));
1✔
143
      }
144
    }
1✔
145
    this.injectionPoints.clear();
1✔
146

147
    // Mappers -----------------------------------------------------------------
148
    for (BeanKey key : mappers) {
1✔
149
      LOGGER.info("MyBatis CDI Module - Managed Mapper dependency: {}, {}", key.getKey(), key.type.getName());
1✔
150
      abd.addBean(key.createBean());
1✔
151
    }
1✔
152
    this.mapperTypes.clear();
1✔
153

154
    // SqlSessionFactories -----------------------------------------------------
155
    for (BeanKey key : this.sessionProducers) {
1✔
156
      LOGGER.info("MyBatis CDI Module - Managed SqlSession: {}, {}", key.getKey(), key.type.getName());
1✔
157
      abd.addBean(key.createBean());
1✔
158
      sessionTargets.remove(key);
1✔
159
    }
1✔
160
    this.sessionProducers.clear();
1✔
161

162
    // Unmanaged SqlSession targets --------------------------------------------
163
    for (BeanKey key : sessionTargets) {
1✔
164
      LOGGER.warn("MyBatis CDI Module - Unmanaged SqlSession: {}, {}", key.getKey(), key.type.getName());
1✔
165
    }
1✔
166

167
  }
1✔
168

169
  /**
170
   * Unique key for fully qualified Mappers and Sessions.
171
   */
172
  private static final class BeanKey implements Comparable<BeanKey> {
173

174
    private final String key;
175

176
    private final List<Annotation> qualifiers;
177

178
    private final Class<Type> type;
179

180
    private final String sqlSessionManagerName;
181

182
    public BeanKey(Class<Type> type, Set<Annotation> annotations) {
1✔
183
      this.type = type;
1✔
184
      this.qualifiers = sort(filterQualifiers(annotations));
1✔
185

186
      // Create key = type(.qualifier)*(.name)?
187
      final StringBuilder sb = new StringBuilder();
1✔
188
      String name = null;
1✔
189
      sb.append(type.getName());
1✔
190
      for (Annotation q : this.qualifiers) {
1✔
191
        if (q instanceof Named) {
1✔
192
          name = ((Named) q).value();
1✔
193
        } else {
194
          sb.append(".").append(q.annotationType().getSimpleName());
1✔
195
        }
196
      }
1✔
197
      if (name != null) {
1✔
198
        sb.append("_").append(name);
1✔
199
      }
200
      this.key = sb.toString();
1✔
201
      this.sqlSessionManagerName = name;
1✔
202
    }
1✔
203

204
    private Set<Annotation> filterQualifiers(Set<Annotation> annotations) {
205
      final Set<Annotation> set = new HashSet<>();
1✔
206
      for (Annotation a : annotations) {
1✔
207
        if (a.annotationType().isAnnotationPresent(Qualifier.class)) {
1✔
208
          set.add(a);
1✔
209
        }
210
      }
1✔
211
      return set;
1✔
212
    }
213

214
    private List<Annotation> sort(Set<Annotation> annotations) {
215
      final List<Annotation> list = new ArrayList<>(annotations);
1✔
216
      Collections.sort(list, (a, b) -> a.getClass().getName().compareTo(b.getClass().getName()));
1✔
217
      return list;
1✔
218
    }
219

220
    @Override
221
    public int compareTo(BeanKey o) {
222
      return this.key.compareTo(o.key);
×
223
    }
224

225
    @Override
226
    public int hashCode() {
227
      int hash = 3;
1✔
228
      return 43 * hash + (this.key != null ? this.key.hashCode() : 0);
1!
229
    }
230

231
    @Override
232
    public boolean equals(Object obj) {
233
      if (obj == null || this.getClass() != obj.getClass()) {
1!
234
        return false;
×
235
      }
236
      final BeanKey other = (BeanKey) obj;
1✔
237
      return !(this.key == null ? other.key != null : !this.key.equals(other.key));
1!
238
    }
239

240
    public MyBatisBean createBean() {
241
      return new MyBatisBean(this.key, this.type, new HashSet<>(this.qualifiers), this.sqlSessionManagerName);
1✔
242
    }
243

244
    public String getKey() {
245
      return this.key;
1✔
246
    }
247

248
    @Override
249
    public String toString() {
250
      return this.key;
×
251
    }
252

253
  }
254

255
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc