001/*
002 *  Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
003 *  <p>
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *  <p>
008 *  http://www.apache.org/licenses/LICENSE-2.0
009 *  <p>
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package com.mybatisflex.core.mybatis;
017
018import com.mybatisflex.core.table.TableInfo;
019import com.mybatisflex.core.table.TableInfoFactory;
020import com.mybatisflex.core.util.StringUtil;
021import org.apache.ibatis.reflection.MetaObject;
022import org.apache.ibatis.reflection.property.PropertyTokenizer;
023import org.apache.ibatis.reflection.wrapper.BeanWrapper;
024import org.apache.ibatis.reflection.wrapper.MapWrapper;
025import org.apache.ibatis.reflection.wrapper.ObjectWrapper;
026import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
027
028import java.util.Collection;
029import java.util.Map;
030
031/**
032 * @author michael
033 */
034public class FlexWrapperFactory implements ObjectWrapperFactory {
035
036    @Override
037    public boolean hasWrapperFor(Object object) {
038        Class<?> objectClass = object.getClass();
039        if (Collection.class.isAssignableFrom(objectClass)) {
040            return false;
041        } else if (Map.class.isAssignableFrom(objectClass)) {
042            return true;
043        }
044        return TableInfoFactory.ofEntityClass(objectClass) != null;
045    }
046
047    @Override
048    public ObjectWrapper getWrapperFor(MetaObject metaObject, Object object) {
049        if (Map.class.isAssignableFrom(object.getClass())) {
050            return new FlexMapWrapper(metaObject, (Map<String, Object>) object);
051        } else {
052            return new FlexBeanWrapper(metaObject, object);
053        }
054    }
055
056    static class FlexBeanWrapper extends BeanWrapper {
057
058        private final Object entity;
059        private final TableInfo tableInfo;
060
061        public FlexBeanWrapper(MetaObject metaObject, Object object) {
062            super(metaObject, object);
063            this.entity = object;
064            this.tableInfo = TableInfoFactory.ofEntityClass(object.getClass());
065        }
066
067        @Override
068        public void set(PropertyTokenizer prop, Object value) {
069            Object v = tableInfo.invokeOnSetListener(entity, prop.getName(), value);
070            super.set(prop, v);
071        }
072    }
073
074
075    static class FlexMapWrapper extends MapWrapper {
076
077        public FlexMapWrapper(MetaObject metaObject, Map<String, Object> map) {
078            super(metaObject, map);
079        }
080
081        @Override
082        public String findProperty(String name, boolean useCamelCaseMapping) {
083            return useCamelCaseMapping && ( Character.isUpperCase(name.charAt(0))  || name.contains("_")) ? StringUtil.underlineToCamel(name) : name;
084        }
085    }
086
087}