private void addUserDefinedMethods(TopLevelClass exampleClass, Interface mapperClass, IntrospectedTable introspectedTable, MyBatisClasses cls) {
        for (Method action : mapperClass.getMethods()) {
            if (!userDefinedMethods.matcher(action.getName()).matches()) continue;
            StringBuilder args = new StringBuilder();
            List<Parameter> params = new ArrayList<Parameter>();
            boolean example = false;
            if (action.getParameters() != null)
                for (Parameter param : action.getParameters()) {
                    String name;
                    if (Objects.equals(param.getType(), exampleClass.getType())) {
                        example = true;
                        name = "this";
                    } else {
                        name = param.getName();
                        params.add(new Parameter(param.getType(), name));
                    }
                    if (args.length() > 0)
                        args.append(", ");
                    args.append(name);
                }
            if (!example) {
                //System.err.println("Invalid user-defined mapper method: "+action.getName());
                continue;
            }

            exampleClass.addMethod(method(
                PUBLIC, INT, action.getName(), _(sqlSession, "sql"), params.toArray(new Parameter[params.size()]), __(
                    "return sql.getMapper(" + cls.names.mapper + ".class)."+action.getName()+"("+args+");"
            )));
            exampleClass.addMethod(method(
                PUBLIC, INT, action.getName(), _(cls.types.mapper, "mapper"), params.toArray(new Parameter[params.size()]), __(
                    "return mapper."+action.getName()+"("+args+");"
            )));
        }
    }
    @Override
    public boolean validate(List<String> strings) {
        listMethod = Objects.nvl(Str.trim(properties.getProperty("listMethodName")), "list");
        listWithBLOBsMethod = Objects.nvl(Str.trim(properties.getProperty("listWithBLOBsMethodName")), listMethod+"WithBLOBs");
        firstMethod = Objects.nvl(Str.trim(properties.getProperty("firstMethodName")), "first");
        firstWithBLOBsMethod = Objects.nvl(Str.trim(properties.getProperty("firstWithBLOBsMethodName")), firstMethod+"WithBLOBs");
        singleMethod = Objects.nvl(Str.trim(properties.getProperty("singleMethodName")), "single");
        singleWithBLOBsMethod = Objects.nvl(Str.trim(properties.getProperty("singleWithBLOBsMethodName")), singleMethod+"WithBLOBs");
        optionalMethod = Objects.nvl(Str.trim(properties.getProperty("optionalMethodName")), "optional");
        optionalWithBLOBsMethod = Objects.nvl(Str.trim(properties.getProperty("optionalWithBLOBsMethodName")), optionalMethod+"WithBLOBs");
        countMethod = Objects.nvl(Str.trim(properties.getProperty("countMethodName")), "count");
        deleteMethod = Objects.nvl(Str.trim(properties.getProperty("deleteMethodName")), "delete");
        updateMethod = Objects.nvl(Str.trim(properties.getProperty("updateMethodName")), "update");
        updateWithBLOBsMethod = Objects.nvl(Str.trim(properties.getProperty("updateWithBLOBsMethodName")), updateMethod+"WithBLOBs");
        updateSelectiveMethod = Objects.nvl(Str.trim(properties.getProperty("updateSelectiveMethodName")), updateMethod+"Selective");
        updateSelectiveWithBLOBsMethod = Objects.nvl(Str.trim(properties.getProperty("updateSelectiveWithBLOBsMethodName")), updateSelectiveMethod+"WithBLOBs");

        generateCriteriaMethods = Bool.bool(Str.trim(properties.getProperty("generateCriteriaMethods")), true);

        userDefinedMethods = Pattern.compile(Objects.nvl(Str.trim(properties.getProperty("userDefinedMethods")), "^(.+WithNull)$"));

        return true;
    }