@TestCoversMethods({"isReadable", "isWritable"})
  public void testIsAccessible() throws Exception {
    SecurityManager securityManager = new SecurityManager();
    FieldAccessController controller = new FieldAccessController(new BaseAccessRule());
    securityManager.addAccessController(controller);
    mapper.setSecurityManager(securityManager);

    Object owner = new Object();
    Object other = new Object();

    POJO1 entity = new POJO1(owner);

    List<com.syncnapsis.utils.reflections.Field> fields = ReflectionsUtil.findFields(POJO1.class);
    assertEquals(3, fields.size());

    com.syncnapsis.utils.reflections.Field xField = fields.get(0);
    assertEquals("x", xField.getName());
    com.syncnapsis.utils.reflections.Field yField = fields.get(1);
    assertEquals("y", yField.getName());
    com.syncnapsis.utils.reflections.Field ownersField = fields.get(2);
    assertEquals("owners", ownersField.getName());

    // READABLE
    // @formatter:off
    Object[][] authorities =
        new Object[][] {
          new Object[] {owner},
          new Object[] {other},
          new Object[] {owner, other},
          null,
          new Object[] {},
        };
    // @formatter:on

    for (int i = 0; i < authorities.length; i++) {
      assertEquals(
          controller.isAccessible(xField, AccessController.READ, entity, authorities[i]),
          mapper.isReadable(entity, xField, authorities[i]));
      assertEquals(
          controller.isAccessible(xField, AccessController.WRITE, entity, authorities[i]),
          mapper.isWritable(entity, xField, authorities[i]));
      assertEquals(
          controller.isAccessible(yField, AccessController.READ, entity, authorities[i]),
          mapper.isReadable(entity, yField, authorities[i]));
      assertEquals(
          controller.isAccessible(yField, AccessController.WRITE, entity, authorities[i]),
          mapper.isWritable(entity, yField, authorities[i]));
    }
  }
  /**
   * Summary function for log(..., Object, ...) and log(..., Exception, ...) which handles the
   * forwarded (partially already serialized) objects.
   *
   * @see RPCLogManager#log(RPCCall, Object, User, HttpSession, Object...)
   * @see RPCLogManager#log(RPCCall, Exception, User, HttpSession, Object...)
   * @param rpcCall - the RPCCall performed
   * @param result - the result or exception returned serialized as a String
   * @param exceptionThrown - did the RPCCall throw an Exception
   * @param executionDate - the execution date
   * @param user - the User that performed the RPCCall
   * @param session - the session in which the RPCCall was executed
   * @param authorities - the authorities used to perform the RPCCall
   */
  protected RPCLog log(
      RPCCall rpcCall,
      String result,
      boolean exceptionThrown,
      Date executionDate,
      User user,
      HttpSession session,
      Object... authorities) {
    com.syncnapsis.data.model.help.RPCCall call = new com.syncnapsis.data.model.help.RPCCall();
    call.setObject(rpcCall.getObject());
    call.setMethod(rpcCall.getMethod());
    try {
      // filter (serialized) arguments (e.g. passwords)
      if (rpcCall.getInvocationInfo() != null && rpcCall.getInvocationInfo().getMethod() != null) {
        LogFilter filter =
            ReflectionsUtil.getAnnotation(rpcCall.getInvocationInfo().getMethod(), LogFilter.class);
        if (filter != null) {
          for (int filteredArg : filter.filteredArgs()) {
            rpcCall.getArgs()[filteredArg] = "****";
          }
        }
      }

      call.setArgs(serializer.serialize(rpcCall.getArgs(), authorities));
    } catch (SerializationException e) {
      logger.error("Could not serialize RPC args: " + e.getMessage());
      call.setArgs(e.getClass().getName() + ": " + e.getMessage());
    }

    String resultS = result;
    if (resultS.length() > Model.LENGTH_TEXT) {
      resultS = resultS.substring(0, Model.LENGTH_TEXT - 5) + " ...";
      if (resultS.startsWith("{")) resultS += "}";
      else if (resultS.startsWith("[")) resultS += "]";
    }

    RPCLog log = new RPCLog();
    log.setExecutionDate(executionDate);
    log.setRemoteAddr(ServletUtil.getRemoteAddr(session));
    log.setResult(resultS);
    log.setRPCCall(call);
    log.setUser(user);
    log.setUserAgent(ServletUtil.getUserAgent(session));
    if (log.getUserAgent() == null) log.setUserAgent(USER_AGENT_NULL);

    if (rpcLogger.isInfoEnabled()) {
      String d = dateFormat.get().format(executionDate);
      rpcLogger.info(
          d
              + "  "
              + log.getRemoteAddr()
              + " -> "
              + call.getObject()
              + "."
              + call.getMethod()
              + "("
              + call.getArgs()
              + ")"
              + (exceptionThrown ? " threw " : " returned ")
              + log.getResult());
    }

    return save(log);
  }