private static void generateSearchMethod(ClassFile cf,
                                             Class beanType,
                                             BeanProperty[] properties)
    {
        MethodInfo mi;
        {
            TypeDesc[] params = {TypeDesc.OBJECT, TypeDesc.OBJECT};
            mi = cf.addMethod(Modifiers.PUBLIC, "hasPropertyValue", TypeDesc.BOOLEAN, params);
        }

        mi.markSynthetic();
        CodeBuilder b = new CodeBuilder(mi);

        LocalVariable beanVar = b.getParameter(0);
        b.loadLocal(beanVar);
        b.checkCast(TypeDesc.forClass(beanType));
        b.storeLocal(beanVar);

        LocalVariable valueVar = b.getParameter(1);

        // If search value is null, only check properties which might be null.
        b.loadLocal(valueVar);
        Label searchNotNull = b.createLabel();
        b.ifNullBranch(searchNotNull, false);

        for (BeanProperty bp : properties) {
            if (bp.getType().isPrimitive()) {
                continue;
            }

            b.loadLocal(beanVar);
            b.invoke(bp.getReadMethod());

            Label noMatch = b.createLabel();
            b.ifNullBranch(noMatch, false);
            b.loadConstant(true);
            b.returnValue(TypeDesc.BOOLEAN);

            noMatch.setLocation();
        }

        b.loadConstant(false);
        b.returnValue(TypeDesc.BOOLEAN);

        searchNotNull.setLocation();

        // Handle search for non-null value. Search non-primitive properties
        // first, to avoid object conversion.

        // Params to invoke Object.equals.
        TypeDesc[] params = {TypeDesc.OBJECT};

        for (int pass = 1; pass <= 2; pass++) {
            for (BeanProperty bp : properties) {
                boolean primitive = bp.getType().isPrimitive();
                if (pass == 1 && primitive) {
                    continue;
                } else if (pass == 2 && !primitive) {
                    continue;
                }

                b.loadLocal(valueVar);
                b.loadLocal(beanVar);
                b.invoke(bp.getReadMethod());
                b.convert(TypeDesc.forClass(bp.getType()), TypeDesc.OBJECT);
                b.invokeVirtual(Object.class.getName(), "equals", TypeDesc.BOOLEAN, params);

                Label noMatch = b.createLabel();
                b.ifZeroComparisonBranch(noMatch, "==");
                b.loadConstant(true);
                b.returnValue(TypeDesc.BOOLEAN);

                noMatch.setLocation();
            }
        }

        b.loadConstant(false);
        b.returnValue(TypeDesc.BOOLEAN);
    }