diff --git a/src/Field.php b/src/Field.php
index 6a0a07e5f771240002f46f65b5fa880bb1faa11a..5dc038c8c9fe096a56b1a2e7aa92fe05826ef36c 100644
--- a/src/Field.php
+++ b/src/Field.php
@@ -270,7 +270,7 @@ class Field
             } catch (InvalidValue $e) {
                 $this->filterFailed = true;
                 $this->errors = $e->errors;
-                return $value;
+                break;
             }
         }
 
@@ -291,12 +291,14 @@ class Field
      */
     public function validate($value, array $context = [])
     {
+        $filtered = $this->filter($value, $context);
+
         if ($this->filterFailed) {
             return false;
         }
 
         try {
-            $hash = md5(serialize([$value, $context]));
+            $hash = md5(serialize([$filtered, $context]));
             if (isset($this->validationCache[$hash])) {
                 return $this->validationCache[$hash];
             }
@@ -308,7 +310,7 @@ class Field
         $valid = true;
         $this->errors = [];
         foreach ($this->validators as $validator) {
-            if (!$validator->validate($value, $context)) {
+            if (!$validator->validate($filtered, $context)) {
                 $valid = false;
                 if ($error = $validator->getError()) {
                     $this->errors[] = $error;
diff --git a/src/Filter.php b/src/Filter.php
index 9bd9db85a4f6e913850fa8210579d00880873c9f..f8f80d1b52f06217c14040cb23f662025d8d560e 100644
--- a/src/Filter.php
+++ b/src/Filter.php
@@ -41,7 +41,7 @@ abstract class Filter implements FilterInterface
     {
         if (is_string($filter)) {
             $filter = Filter::fromString($filter);
-        } elseif (is_callable($filter)) {
+        } elseif (is_callable($filter) && !$filter instanceof FilterInterface) {
             $filter = new Filter\Callback($filter);
         }
 
@@ -81,6 +81,19 @@ abstract class Filter implements FilterInterface
         return static::create(ucfirst($name), $arguments);
     }
 
+    /**
+     * Call the filter is an alias for filter
+     *
+     * @param mixed $value
+     * @param array $context
+     * @return mixed
+     */
+    public function __invoke($value, array $context = [])
+    {
+        return $this->filter($value, $context);
+    }
+
+
     /**
      * Create a filter dynamically
      *
diff --git a/src/FilterInterface.php b/src/FilterInterface.php
index 6a1f8cd164a5fd8eecf835c894004dfb1d10bd14..ff730fcb48ba136a2d173d7df3fd75eb36676940 100644
--- a/src/FilterInterface.php
+++ b/src/FilterInterface.php
@@ -13,6 +13,15 @@ interface FilterInterface
      */
     public function filter($value, array $context = []);
 
+    /**
+     * Call the filter is an alias for filter
+     *
+     * @param mixed $value
+     * @param array $context
+     * @return mixed
+     */
+    public function __invoke($value, array $context = []);
+
     /**
      * Assign filter to $field
      *
diff --git a/src/Gate.php b/src/Gate.php
index b027132fa8643466e8f05f4c8d4963bff6f705a1..143a78ca233ed0fbd4cae7fbd604ef2abd5df495 100644
--- a/src/Gate.php
+++ b/src/Gate.php
@@ -210,9 +210,9 @@ class Gate
 
         $result  = [];
         foreach ($fields as $k => $field) {
-            $filtered = $field->filter(isset($this->rawData[$k]) ? $this->rawData[$k] : null, $this->rawData);
+            $filtered = $field->filter($this->rawData[$k] ?? null, $this->rawData);
 
-            if ($validate && !$field->validate($filtered, $this->rawData)) {
+            if ($validate && !$field->validate($this->rawData[$k] ?? null, $this->rawData)) {
                 if ($field->isRequired()) {
                     $errors = $field->getErrors();
                     if (count($errors) > 0) {
@@ -239,8 +239,9 @@ class Gate
      *
      * @param string $key
      * @return mixed
-     * @see Gate::getData()
+     * @see                Gate::getData()
      * @codeCoverageIgnore trivial
+     * @throws InvalidValue
      */
     public function get(string $key = null)
     {
@@ -252,14 +253,21 @@ class Gate
      *
      * @param string $key
      * @return mixed
-     * @see Gate::getData()
+     * @see                Gate::getData()
      * @codeCoverageIgnore trivial
+     * @throws InvalidValue
      */
     public function __get(string $key)
     {
         return $this->getData($key);
     }
 
+    /**
+     * Validate $data or previously stored data
+     *
+     * @param array $data
+     * @return bool
+     */
     public function validate(array $data = null)
     {
         if ($data) {
@@ -268,13 +276,12 @@ class Gate
 
         $valid = true;
         $this->errors = [];
-        $filtered = $this->getData(null, false);
         foreach ($this->fields as $key => $field) {
-            if (empty($filtered[$key]) && !$field->isRequired()) {
+            if (empty($this->rawData[$key]) && !$field->isRequired()) {
                 continue;
             }
 
-            if (!$field->validate($filtered[$key], $this->rawData)) {
+            if (!$field->validate($this->rawData[$key] ?? null, $this->rawData)) {
                 $valid = false;
                 $this->errors[$key] = $field->getErrors();
             }
diff --git a/src/Validator.php b/src/Validator.php
index 29e526bb7bddd45c4e1002a309bb6c495ccba893..dffb010e491c6b284c38944e7a2d94fc5ecfd31e 100644
--- a/src/Validator.php
+++ b/src/Validator.php
@@ -57,7 +57,7 @@ abstract class Validator implements ValidatorInterface
     {
         if (is_string($validator)) {
             $validator = static::fromString($validator);
-        } elseif (is_callable($validator)) {
+        } elseif (is_callable($validator) && !$validator instanceof ValidatorInterface) {
             $validator = new Validator\Callback($validator);
         }
 
@@ -101,6 +101,18 @@ abstract class Validator implements ValidatorInterface
         return static::create(ucfirst($name), $arguments);
     }
 
+    /**
+     * Call the validator is an alias for validate
+     *
+     * @param mixed $value
+     * @param array $context
+     * @return bool
+     */
+    public function __invoke($value, array $context = []): bool
+    {
+        return $this->validate($value, $context);
+    }
+
     /**
      * Create a validator dynamically
      *
diff --git a/src/ValidatorInterface.php b/src/ValidatorInterface.php
index 76ba5d76fde04a46ea06732dbe40949974e2cfd3..3b4fc4c5455fccdc0dfd5b703758ae377084f17f 100644
--- a/src/ValidatorInterface.php
+++ b/src/ValidatorInterface.php
@@ -13,6 +13,15 @@ interface ValidatorInterface
      */
     public function validate($value, array $context = []): bool;
 
+    /**
+     * Call the validator is an alias for validate
+     *
+     * @param mixed $value
+     * @param array $context
+     * @return bool
+     */
+    public function __invoke($value, array $context = []): bool;
+
     /**
      * Assign validator to $field
      *
diff --git a/tests/Field/ValidatorTest.php b/tests/Field/ValidatorTest.php
index e1273561327a5b5fde52ef4df13d0e4b084ebbbc..36d46bc0a2fccb212db2f95689703dd9230e8616 100644
--- a/tests/Field/ValidatorTest.php
+++ b/tests/Field/ValidatorTest.php
@@ -156,4 +156,21 @@ class ValidatorTest extends TestCase
         $field->addValidator('notEmpty');
         $field->validate(' body ');
     }
+
+    /** @test */
+    public function executesFilterBeforeValidation()
+    {
+        $field = \Mockery::mock(Field::class)->makePartial();
+        $validator = \Mockery::mock(NotEmpty::class)->makePartial();
+        $field->addValidator($validator);
+
+        $field->shouldReceive('filter')
+            ->with('value', [])
+            ->once()->andReturn(42);
+        $validator->shouldReceive('validate')
+            ->with(42, [])
+            ->once()->andReturn(true);
+
+        $field->validate('value');
+    }
 }
diff --git a/tests/Filter/CommonTest.php b/tests/Filter/CommonTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..6b480c2c4fa9deb8ea816a9a28ebdd3104d523e4
--- /dev/null
+++ b/tests/Filter/CommonTest.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace Verja\Test\Filter;
+
+use Verja\Filter\Trim;
+use Verja\Test\TestCase;
+
+class CommonTest extends TestCase
+{
+    /** @test */
+    public function filterIsInvokable()
+    {
+        $filter = new Trim();
+
+        $result = $filter(' foo bar ');
+
+        self::assertSame('foo bar', $result);
+    }
+}
diff --git a/tests/Gate/GetDataTest.php b/tests/Gate/GetDataTest.php
index ffc80978fb5d510b27060565f628153e1bdd0752..637356d7094aab0b1e6046d0588a5491c565451e 100644
--- a/tests/Gate/GetDataTest.php
+++ b/tests/Gate/GetDataTest.php
@@ -40,7 +40,7 @@ class GetDataTest extends TestCase
         $gate->addField('username', $field);
 
         $field->shouldReceive('filter')->with('john', ['username' => 'john', 'password' => 'abc123'])
-            ->once()->andReturn('john');
+            ->atLeast()->once()->andReturn('john');
 
         $gate->getData();
     }
@@ -50,10 +50,10 @@ class GetDataTest extends TestCase
     {
         $gate = new Gate([ 'username' => 'john@example', 'password' => 'abc123' ]);
         $field = \Mockery::mock(Field::class)->makePartial();
-        $field->shouldReceive('filter')->andReturn('john');
         $gate->addField('username', $field);
 
-        $field->shouldReceive('validate')->with('john', ['username' => 'john@example', 'password' => 'abc123'])
+        $field->shouldReceive('validate')
+            ->with('john@example', ['username' => 'john@example', 'password' => 'abc123'])
             ->once()->andReturn(true);
 
         $gate->getData();
diff --git a/tests/Gate/ValidateTest.php b/tests/Gate/ValidateTest.php
index da5db22afef667e4d2ed54e0e12d6245054c7c21..13706deb00458775dd045ec4d21884a10731304d 100644
--- a/tests/Gate/ValidateTest.php
+++ b/tests/Gate/ValidateTest.php
@@ -58,21 +58,6 @@ class ValidateTest extends TestCase
         self::assertFalse($result);
     }
 
-    /** @test */
-    public function usesFilteredValueForValidation()
-    {
-        $field = \Mockery::mock(Field::class)->makePartial();
-        $field->shouldReceive('filter')->with('value', [ 'f' => 'value' ])->once()->andReturn(42);
-        $field->shouldReceive('validate')->with(42, [ 'f' => 'value' ])->once()->andReturn(true);
-
-        $gate = new Gate([ 'f' => 'value' ]);
-        $gate->addField('f', $field);
-
-        $result = $gate->validate();
-
-        self::assertTrue($result);
-    }
-
     /** @test */
     public function validatesGivenArray()
     {
diff --git a/tests/Validator/CommonTest.php b/tests/Validator/CommonTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..04e1a800aec64c88fe2bb213d5ef08585000b012
--- /dev/null
+++ b/tests/Validator/CommonTest.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace Verja\Test\Validator;
+
+use Verja\Test\TestCase;
+use Verja\Validator\NotEmpty;
+
+class CommonTest extends TestCase
+{
+    /** @test */
+    public function validatorIsInvokable()
+    {
+        $validator = new NotEmpty();
+
+        $result = $validator('foo');
+
+        self::assertTrue($result);
+    }
+}