@Override
    public Collection<String> getGroupNames(JID user) {
        user = user.asBareJID();
        List<String> groupNames = new ArrayList<>();
        Connection con = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            // OF-1837: When the database does not hold escaped data, our query should use unescaped values in the 'where' clause.
            final String queryValue;
            if ( server.isLocal(user) ) {
                queryValue = assumePersistedDataIsEscaped() ? user.getNode() : JID.unescapeNode( user.getNode() );
            } else {
                String value = user.toString();
                final int splitIndex = value.lastIndexOf( "@" );
                final String node = value.substring( 0, splitIndex );
                final String processedNode = assumePersistedDataIsEscaped() ? node : JID.unescapeNode( node );
                queryValue = processedNode + value.substring( splitIndex );
            }
            con = getConnection();
            pstmt = con.prepareStatement(userGroupsSQL);
            pstmt.setString(1, queryValue);
            rs = pstmt.executeQuery();
            while (rs.next()) {
                groupNames.add(rs.getString(1));
            }
        }
        catch (SQLException e) {
            Log.error(e.getMessage(), e);
        }
        finally {
            DbConnectionManager.closeConnection(rs, pstmt, con);
        }
        return groupNames;
    }
XMPP disallows some characters in identifiers, requiring them to be escaped.

This implementation assumes that the database returns properly escaped identifiers,
but can apply escaping by setting the value of the 'jdbcGroupProvider.isEscaped'
property to 'false'.

@return 'false' if this implementation needs to escape database content before processing.
xmppserver/src/main/java/org/jivesoftware/openfire/group/JDBCGroupProvider.java