JAMES-1664 refactoring of getMessages handling to make it simpler with a bit of 
encapsulation


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/4c8403c3
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/4c8403c3
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/4c8403c3

Branch: refs/heads/master
Commit: 4c8403c34a2f0e2bb620fda41853dce1ec54f3ae
Parents: 8c19208
Author: Matthieu Baechler <matthieu.baech...@gmail.com>
Authored: Wed Jan 27 09:59:52 2016 +0100
Committer: Antoine Duprat <antdup...@gmail.com>
Committed: Mon Feb 1 13:21:05 2016 +0100

----------------------------------------------------------------------
 .../jmap/json/FieldNamePropertyFilter.java      |  41 +++
 .../james/jmap/methods/GetMessagesMethod.java   |  97 ++------
 .../jmap/methods/JmapResponseWriterImpl.java    |   1 +
 .../james/jmap/model/GetMessagesRequest.java    |  57 +----
 .../james/jmap/model/MessageHeaderProperty.java |  69 ------
 .../james/jmap/model/MessageProperties.java     | 248 +++++++++++++++++++
 .../james/jmap/model/MessageProperty.java       |  69 ------
 .../jmap/methods/GetMessagesMethodTest.java     |  19 +-
 .../jmap/model/GetMessagesRequestTest.java      |  14 +-
 .../jmap/model/MessageHeaderPropertyTest.java   |  44 +++-
 .../james/jmap/model/MessagePropertiesTest.java |  82 ++++++
 .../james/jmap/model/MessagePropertyTest.java   |   3 +-
 12 files changed, 455 insertions(+), 289 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/4c8403c3/server/protocols/jmap/src/main/java/org/apache/james/jmap/json/FieldNamePropertyFilter.java
----------------------------------------------------------------------
diff --git 
a/server/protocols/jmap/src/main/java/org/apache/james/jmap/json/FieldNamePropertyFilter.java
 
b/server/protocols/jmap/src/main/java/org/apache/james/jmap/json/FieldNamePropertyFilter.java
new file mode 100644
index 0000000..40766cc
--- /dev/null
+++ 
b/server/protocols/jmap/src/main/java/org/apache/james/jmap/json/FieldNamePropertyFilter.java
@@ -0,0 +1,41 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.jmap.json;
+
+
+import com.fasterxml.jackson.databind.ser.PropertyWriter;
+import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
+
+import java.util.function.Predicate;
+
+public class FieldNamePropertyFilter extends SimpleBeanPropertyFilter {
+
+    private final Predicate<String> predicate;
+
+    public FieldNamePropertyFilter(Predicate<String> predicate) {
+        this.predicate = predicate;
+    }
+
+    @Override
+    protected boolean include(PropertyWriter writer) {
+        return predicate.test(writer.getName());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/4c8403c3/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/GetMessagesMethod.java
----------------------------------------------------------------------
diff --git 
a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/GetMessagesMethod.java
 
b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/GetMessagesMethod.java
index e030d3f..a2ad348 100644
--- 
a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/GetMessagesMethod.java
+++ 
b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/GetMessagesMethod.java
@@ -22,7 +22,6 @@ package org.apache.james.jmap.methods;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Optional;
-import java.util.Set;
 import java.util.function.Function;
 import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
@@ -30,14 +29,14 @@ import java.util.stream.StreamSupport;
 import javax.inject.Inject;
 
 import org.apache.commons.lang.NotImplementedException;
+import org.apache.james.jmap.json.FieldNamePropertyFilter;
 import org.apache.james.jmap.model.ClientId;
 import org.apache.james.jmap.model.GetMessagesRequest;
 import org.apache.james.jmap.model.GetMessagesResponse;
 import org.apache.james.jmap.model.Message;
-import org.apache.james.jmap.model.MessageHeaderProperty;
 import org.apache.james.jmap.model.MessageId;
-import org.apache.james.jmap.model.MessageProperty;
-import org.apache.james.jmap.model.Property;
+import org.apache.james.jmap.model.MessageProperties;
+import org.apache.james.jmap.model.MessageProperties.HeaderProperty;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.model.MessageRange;
@@ -50,18 +49,15 @@ import 
org.apache.james.mailbox.store.mail.model.MailboxMessage;
 import org.apache.james.util.streams.Collectors;
 import org.javatuples.Pair;
 
-import com.fasterxml.jackson.databind.ser.PropertyWriter;
-import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
+import com.fasterxml.jackson.databind.ser.PropertyFilter;
 import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
 import com.github.fge.lambdas.Throwing;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
 
 public class GetMessagesMethod<Id extends MailboxId> implements Method {
 
-    public static final Set<MessageProperty> MANDATORY_PROPERTIES = 
ImmutableSet.of(MessageProperty.id, MessageProperty.threadId, 
MessageProperty.mailboxIds);
     public static final String HEADERS_FILTER = "headersFilter";
     private static final Method.Request.Name METHOD_NAME = 
Method.Request.name("getMessages");
     private static final Method.Response.Name RESPONSE_NAME = 
Method.Response.name("messages");
@@ -92,88 +88,27 @@ public class GetMessagesMethod<Id extends MailboxId> 
implements Method {
         Preconditions.checkNotNull(mailboxSession);
         Preconditions.checkArgument(request instanceof GetMessagesRequest);
         GetMessagesRequest getMessagesRequest = (GetMessagesRequest) request;
-        Optional<ImmutableSet<MessageProperty>> requestedProperties = 
getMessagesRequest.getProperties();
-        Optional<ImmutableSet<MessageHeaderProperty>> headerProperties = 
getMessagesRequest.getHeaderProperties();
+        MessageProperties outputProperties = 
getMessagesRequest.getProperties().toOutputProperties();
         return Stream.of(JmapResponse.builder().clientId(clientId)
-                            .response(getMessagesResponse(mailboxSession, 
getMessagesRequest, requestedProperties))
+                            .response(getMessagesResponse(mailboxSession, 
getMessagesRequest))
                             .responseName(RESPONSE_NAME)
-                            
.properties(handleSpecificProperties(requestedProperties, headerProperties))
-                            
.filterProvider(Optional.of(buildFilteringHeadersFilterProvider(headerProperties)))
+                            
.properties(outputProperties.getOptionalMessageProperties())
+                            
.filterProvider(buildOptionalHeadersFilteringFilterProvider(outputProperties))
                             .build());
     }
 
-    private Optional<Set<? extends Property>> 
handleSpecificProperties(Optional<ImmutableSet<MessageProperty>> 
requestedProperties, Optional<ImmutableSet<MessageHeaderProperty>> 
headerProperties) {
-        Set<MessageProperty> toAdd = Sets.newHashSet();
-        Set<MessageProperty> toRemove = Sets.newHashSet();
-        toAdd.addAll(ensureContainsMandatoryFields(requestedProperties));
-        handleBody(requestedProperties, toAdd, toRemove);
-        handleHeadersProperties(headerProperties, toAdd, toRemove);
-        ImmutableSet<MessageProperty> resultProperties = Sets.union(
-                    Sets.difference(requestedProperties.isPresent() ? 
requestedProperties.get() : ImmutableSet.of(), toRemove)
-                    , toAdd)
-                .immutableCopy();
-        if (resultProperties.isEmpty()) {
-            return Optional.empty();
-        }
-        return Optional.of(resultProperties);
-    }
-
-    private void 
handleHeadersProperties(Optional<ImmutableSet<MessageHeaderProperty>> 
headerProperties, Set<MessageProperty> toAdd, Set<MessageProperty> toRemove) {
-        if (headerProperties.isPresent() && !headerProperties.get().isEmpty()) 
{
-            toAdd.add(MessageProperty.headers);
-        }
-    }
-
-    private Set<MessageProperty> 
ensureContainsMandatoryFields(Optional<ImmutableSet<MessageProperty>> 
requestedProperties) {
-        return MANDATORY_PROPERTIES.stream()
-            .filter(mandatoryProperty -> propertyToAdd(mandatoryProperty, 
requestedProperties))
-            .collect(Collectors.toImmutableSet());
-    }
-
-    private boolean propertyToAdd(MessageProperty property, 
Optional<ImmutableSet<MessageProperty>> requestedProperties) {
-        return requestedProperties.isPresent() && 
-                !requestedProperties
-                    .filter(properties -> properties.contains(property))
-                    .flatMap(Optional::of)
-                    .isPresent();
-    }
-
-    private void handleBody(Optional<ImmutableSet<MessageProperty>> 
requestedProperties, Set<MessageProperty> toAdd, Set<MessageProperty> toRemove) 
{
-        if (requestedProperties.isPresent() && 
requestedProperties.get().contains(MessageProperty.body)) {
-            toAdd.add(MessageProperty.textBody);
-            toRemove.add(MessageProperty.body);
-        }
-    }
-
-    private SimpleFilterProvider 
buildFilteringHeadersFilterProvider(Optional<ImmutableSet<MessageHeaderProperty>>
 headerProperties) {
-        return new SimpleFilterProvider()
-                .addFilter(HEADERS_FILTER, 
buildPropertyFilter(headerProperties))
-                .addFilter(JmapResponseWriterImpl.PROPERTIES_FILTER, 
SimpleBeanPropertyFilter.serializeAll());
+    private Optional<SimpleFilterProvider> 
buildOptionalHeadersFilteringFilterProvider(MessageProperties properties) {
+        return properties.getOptionalHeadersProperties()
+            .map(this::buildHeadersPropertyFilter)
+            .map(propertyFilter -> new SimpleFilterProvider()
+                .addFilter(HEADERS_FILTER, propertyFilter));
     }
     
-    private SimpleBeanPropertyFilter 
buildPropertyFilter(Optional<ImmutableSet<MessageHeaderProperty>> 
headerProperties) {
-        if (!headerProperties.isPresent()) {
-            return SimpleBeanPropertyFilter.serializeAll();
-        } else {
-            return new 
IncludeMessagePropertyPropertyFilter(headerProperties.get());
-        }
+    private PropertyFilter 
buildHeadersPropertyFilter(ImmutableSet<HeaderProperty> headerProperties) {
+        return new FieldNamePropertyFilter((fieldName) -> 
headerProperties.contains(HeaderProperty.fromFieldName(fieldName)));
     }
-    
-    private static class IncludeMessagePropertyPropertyFilter extends 
SimpleBeanPropertyFilter {
-        private final Set<MessageHeaderProperty> propertiesToInclude;
 
-        public IncludeMessagePropertyPropertyFilter(Set<MessageHeaderProperty> 
propertiesToInclude) {
-            this.propertiesToInclude = propertiesToInclude;
-        }
-        
-        @Override
-        protected boolean include(PropertyWriter writer) {
-            String currentProperty = writer.getName();
-            return 
propertiesToInclude.contains(MessageHeaderProperty.fromField(currentProperty));
-        }
-    }
-    
-    private GetMessagesResponse getMessagesResponse(MailboxSession 
mailboxSession, GetMessagesRequest getMessagesRequest, 
Optional<ImmutableSet<MessageProperty>> requestedProperties) {
+    private GetMessagesResponse getMessagesResponse(MailboxSession 
mailboxSession, GetMessagesRequest getMessagesRequest) {
         
getMessagesRequest.getAccountId().ifPresent(GetMessagesMethod::notImplemented);
         
         Function<MessageId, Stream<Pair<MailboxMessage<Id>, MailboxPath>>> 
loadMessages = loadMessage(mailboxSession);

http://git-wip-us.apache.org/repos/asf/james-project/blob/4c8403c3/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/JmapResponseWriterImpl.java
----------------------------------------------------------------------
diff --git 
a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/JmapResponseWriterImpl.java
 
b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/JmapResponseWriterImpl.java
index 2ddbc42..f56a067 100644
--- 
a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/JmapResponseWriterImpl.java
+++ 
b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/JmapResponseWriterImpl.java
@@ -67,6 +67,7 @@ public class JmapResponseWriterImpl implements 
JmapResponseWriter {
         FilterProvider filterProvider = jmapResponse
                 .getFilterProvider()
                 .orElseGet(SimpleFilterProvider::new)
+                .setDefaultFilter(SimpleBeanPropertyFilter.serializeAll())
                 .addFilter(PROPERTIES_FILTER, 
getPropertiesFilter(jmapResponse.getProperties()));
         
         objectMapper.setFilterProvider(filterProvider);

http://git-wip-us.apache.org/repos/asf/james-project/blob/4c8403c3/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/GetMessagesRequest.java
----------------------------------------------------------------------
diff --git 
a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/GetMessagesRequest.java
 
b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/GetMessagesRequest.java
index 708dc3d..4b67c55 100644
--- 
a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/GetMessagesRequest.java
+++ 
b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/GetMessagesRequest.java
@@ -23,7 +23,6 @@ import java.util.List;
 import java.util.Optional;
 
 import org.apache.james.jmap.methods.JmapRequest;
-import org.apache.james.util.streams.Collectors;
 
 import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
 import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
@@ -42,12 +41,12 @@ public class GetMessagesRequest implements JmapRequest {
         
         private Optional<String> accountId;
         private final ImmutableList.Builder<MessageId> ids;
-        private ImmutableSet.Builder<String> propertiesBuilder;
+        private Optional<ImmutableSet<String>> properties;
 
         private Builder() {
             accountId = Optional.empty();
             ids = ImmutableList.builder();
-            propertiesBuilder = null;
+            properties = Optional.empty();
         }
         
         public Builder accountId(String accountId) {
@@ -61,59 +60,23 @@ public class GetMessagesRequest implements JmapRequest {
         }
 
         public Builder properties(List<String> properties) {
-            if (propertiesBuilder == null) {
-                propertiesBuilder = ImmutableSet.builder();
-            }
-            this.propertiesBuilder.addAll(properties);
+            this.properties = 
Optional.ofNullable(properties).map(ImmutableSet::copyOf);
             return this;
         }
         
         public GetMessagesRequest build() {
-            return new GetMessagesRequest(accountId, ids.build(), 
messageProperties(propertiesBuilder), 
messageHeaderProperties(propertiesBuilder));
-        }
-
-        private Optional<ImmutableSet<MessageProperty>> 
messageProperties(ImmutableSet.Builder<String> messageProperties) {
-            if (messageProperties == null) {
-                return Optional.empty();
-            }
-            return toOptional(messageProperties.build().stream()
-                        .filter(property -> !isHeaderProperty(property))
-                        .map(MessageProperty::valueOf)
-                        .collect(Collectors.toImmutableSet()),
-                    MessageProperty.class);
-        }
-
-        private Optional<ImmutableSet<MessageHeaderProperty>> 
messageHeaderProperties(ImmutableSet.Builder<String> headerProperties) {
-            if (headerProperties == null) {
-                return Optional.empty();
-            }
-            return toOptional(headerProperties.build().stream()
-                        .filter(this::isHeaderProperty)
-                        .map(MessageHeaderProperty::valueOf)
-                        .collect(Collectors.toImmutableSet()),
-                    MessageHeaderProperty.class);
-        }
-
-        private boolean isHeaderProperty(String property) {
-            return 
property.startsWith(MessageHeaderProperty.HEADER_PROPERTY_PREFIX);
-        }
-
-        private <T extends Property> Optional<ImmutableSet<T>> 
toOptional(ImmutableSet<T> set, Class<T> clazz) {
-            return Optional.of(set);
+            return new GetMessagesRequest(accountId, ids.build(), new 
MessageProperties(properties));
         }
     }
-
+    
     private final Optional<String> accountId;
     private final ImmutableList<MessageId> ids;
-    private final Optional<ImmutableSet<MessageProperty>> properties;
-    private final Optional<ImmutableSet<MessageHeaderProperty>> 
headerProperties;
+    private final MessageProperties properties;
 
-    public GetMessagesRequest(Optional<String> accountId, 
ImmutableList<MessageId> ids, 
-            Optional<ImmutableSet<MessageProperty>> properties, 
Optional<ImmutableSet<MessageHeaderProperty>> headerProperties) {
+    public GetMessagesRequest(Optional<String> accountId, 
ImmutableList<MessageId> ids, MessageProperties properties) {
         this.accountId = accountId;
         this.ids = ids;
         this.properties = properties;
-        this.headerProperties = headerProperties;
     }
     
     public Optional<String> getAccountId() {
@@ -124,11 +87,7 @@ public class GetMessagesRequest implements JmapRequest {
         return ids;
     }
     
-    public Optional<ImmutableSet<MessageProperty>> getProperties() {
+    public MessageProperties getProperties() {
         return properties;
     }
-
-    public Optional<ImmutableSet<MessageHeaderProperty>> getHeaderProperties() 
{
-        return headerProperties;
-    }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/4c8403c3/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageHeaderProperty.java
----------------------------------------------------------------------
diff --git 
a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageHeaderProperty.java
 
b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageHeaderProperty.java
deleted file mode 100644
index 4a51415..0000000
--- 
a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageHeaderProperty.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-package org.apache.james.jmap.model;
-
-import java.util.Locale;
-import java.util.Objects;
-
-public class MessageHeaderProperty implements Property {
-
-    public static final String HEADER_PROPERTY_PREFIX = "headers.";
-
-    public static MessageHeaderProperty from(MessageProperty messageProperty) {
-        return new MessageHeaderProperty(HEADER_PROPERTY_PREFIX + 
messageProperty.asFieldName().toLowerCase(Locale.US));
-    }
-
-    public static MessageHeaderProperty fromField(String field) {
-        return new MessageHeaderProperty(HEADER_PROPERTY_PREFIX + 
field.toLowerCase(Locale.US));
-    }
-
-    public static MessageHeaderProperty valueOf(String property) {
-        return new MessageHeaderProperty(property.toLowerCase(Locale.US));
-    }
-
-    private String property;
-
-    private MessageHeaderProperty(String property) {
-        this.property = property;
-    }
-
-    @Override
-    public String asFieldName() {
-        return property;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (obj instanceof MessageHeaderProperty) {
-            MessageHeaderProperty other = (MessageHeaderProperty) obj;
-            return Objects.equals(this.property, other.property);
-        }
-        return false;
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(property);
-    }
-
-    @Override
-    public String toString() {
-        return Objects.toString(property);
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/4c8403c3/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageProperties.java
----------------------------------------------------------------------
diff --git 
a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageProperties.java
 
b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageProperties.java
new file mode 100644
index 0000000..a24bf9a
--- /dev/null
+++ 
b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageProperties.java
@@ -0,0 +1,248 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.james.jmap.model;
+
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import com.google.common.collect.Sets;
+import org.apache.james.util.streams.Collectors;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableSet;
+
+public class MessageProperties {
+
+    public static final ImmutableSet<MessageProperty> MANDATORY_PROPERTIES = 
ImmutableSet.of(MessageProperty.id, MessageProperty.threadId, 
MessageProperty.mailboxIds);
+
+    private final Optional<ImmutableSet<MessageProperty>> messageProperties;
+    private final Optional<ImmutableSet<HeaderProperty>> headersProperties;
+
+    public MessageProperties(Optional<ImmutableSet<String>> properties) {
+        this.messageProperties = properties.map(this::toMessageProperties);
+        this.headersProperties = properties.map(this::toHeadersProperties);
+    }
+
+    private MessageProperties(Optional<ImmutableSet<MessageProperty>> 
messageProperties,
+                              Optional<ImmutableSet<HeaderProperty>> 
headersProperties) {
+        this.messageProperties = messageProperties;
+        this.headersProperties = headersProperties;
+    }
+
+    private ImmutableSet<MessageProperty> 
toMessageProperties(ImmutableSet<String> properties) {
+        return 
properties.stream().flatMap(MessageProperty::find).collect(Collectors.toImmutableSet());
+    }
+    
+    private ImmutableSet<HeaderProperty> 
toHeadersProperties(ImmutableSet<String> properties) {
+        return 
properties.stream().flatMap(HeaderProperty::find).collect(Collectors.toImmutableSet());
+    }
+
+    public Optional<ImmutableSet<HeaderProperty>> 
getOptionalHeadersProperties() {
+        return headersProperties;
+    }
+    
+    public Optional<ImmutableSet<MessageProperty>> 
getOptionalMessageProperties() {
+        return messageProperties;
+    }
+
+    public MessageProperties toOutputProperties() {
+        return this.ensureContains(MANDATORY_PROPERTIES)
+                .selectBody()
+                .overrideHeadersFilteringOnHeadersMessageProperty()
+                .ensureHeadersMessageProperty();
+    }
+
+    private ImmutableSet<MessageProperty> buildOutputMessageProperties() {
+        return this.messageProperties.orElseGet(() -> 
MessageProperty.allOutputProperties());
+    }
+
+    private MessageProperties usingProperties(Sets.SetView<MessageProperty> 
properties) {
+        return new MessageProperties(
+            Optional.of(properties.immutableCopy()),
+            headersProperties);
+    }
+
+    private MessageProperties ensureContains(ImmutableSet<MessageProperty> 
mandatoryFields) {
+        return usingProperties(Sets.union(buildOutputMessageProperties(), 
mandatoryFields));
+    }
+
+    private MessageProperties selectBody() {
+        ImmutableSet<MessageProperty> messageProperties = 
buildOutputMessageProperties();
+        if (messageProperties.contains(MessageProperty.body)) {
+            return usingProperties(
+                Sets.difference(
+                    Sets.union(messageProperties, 
ImmutableSet.of(MessageProperty.textBody)),
+                    ImmutableSet.of(MessageProperty.body)));
+        }
+        return this;
+    }
+
+    private MessageProperties ensureHeadersMessageProperty() {
+        if (headersProperties.isPresent() && 
!headersProperties.get().isEmpty()) {
+            return usingProperties(Sets.union(
+                buildOutputMessageProperties(),
+                ImmutableSet.of(MessageProperty.headers)));
+        }
+        return this;
+    }
+
+    private MessageProperties 
overrideHeadersFilteringOnHeadersMessageProperty() {
+        if (buildOutputMessageProperties().contains(MessageProperty.headers)) {
+            return new MessageProperties(messageProperties, Optional.empty());
+        }
+        return this;
+    }
+
+
+    private enum PropertyType {
+        INPUTONLY,
+        INPUTOUTPUT
+    }
+
+    public enum MessageProperty implements Property {
+        id("id"),
+        blobId("blobId"),
+        threadId("threadId"),
+        mailboxIds("mailboxIds"),
+        inReplyToMessageId("inReplyToMessageId"),
+        isUnread("isUnread"),
+        isFlagged("isFlagged"),
+        isAnswered("isAnswered"),
+        isDraft("isDraft"),
+        hasAttachment("hasAttachment"),
+        headers("headers"),
+        from("from"),
+        to("to"),
+        cc("cc"),
+        bcc("bcc"),
+        replyTo("replyTo"),
+        subject("subject"),
+        date("date"),
+        size("size"),
+        preview("preview"),
+        textBody("textBody"),
+        htmlBody("htmlBody"),
+        attachments("attachments"),
+        attachedMessages("attachedMessages"),
+        body("body", PropertyType.INPUTONLY);
+    
+        private final String property;
+        private final PropertyType type;
+
+        MessageProperty(String property) {
+            this(property, PropertyType.INPUTOUTPUT);
+        }
+
+        MessageProperty(String property, PropertyType type) {
+            this.property = property;
+            this.type = type;
+        }
+    
+        @Override
+        public String asFieldName() {
+            return property;
+        }
+    
+        public static Stream<MessageProperty> find(String property) {
+            Preconditions.checkNotNull(property);
+            return Arrays.stream(values()).filter(entry -> 
entry.property.equals(property));
+        }
+
+        public static ImmutableSet<MessageProperty> allOutputProperties() {
+            return 
Arrays.stream(values()).filter(MessageProperty::outputProperty).collect(Collectors.toImmutableSet());
+        }
+
+        private static boolean outputProperty(MessageProperty p) {
+            switch (p.type) {
+                case INPUTONLY:
+                    return false;
+                case INPUTOUTPUT:
+                    return true;
+                default:
+                    throw new IllegalStateException();
+            }
+        }
+    }
+    
+
+    public static class HeaderProperty implements Property {
+    
+        public static final String HEADER_PROPERTY_PREFIX = "headers.";
+
+        public static HeaderProperty fromFieldName(String field) {
+            Preconditions.checkArgument(!isMessageHeaderProperty(field));
+            return new HeaderProperty(field.toLowerCase(Locale.US));
+        }
+    
+        public static HeaderProperty valueOf(String property) {
+            Preconditions.checkArgument(isMessageHeaderProperty(property));
+            return new 
HeaderProperty(stripPrefix(property).toLowerCase(Locale.US));
+        }
+
+        private static String stripPrefix(String property) {
+            return property.substring(HEADER_PROPERTY_PREFIX.length());
+        }
+
+        public static boolean isMessageHeaderProperty(String property) {
+            Preconditions.checkNotNull(property);
+            return property.startsWith(HEADER_PROPERTY_PREFIX);
+        }
+        
+        public static Stream<HeaderProperty> find(String property) {
+            if (isMessageHeaderProperty(property)) {
+                return Stream.of(valueOf(property));
+            } else {
+                return Stream.of();
+            }
+        }
+        
+        private String fieldName;
+    
+        private HeaderProperty(String fieldName) {
+            this.fieldName = fieldName;
+        }
+    
+        @Override
+        public String asFieldName() {
+            return fieldName;
+        }
+    
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof HeaderProperty) {
+                HeaderProperty other = (HeaderProperty) obj;
+                return Objects.equals(this.fieldName, other.fieldName);
+            }
+            return false;
+        }
+    
+        @Override
+        public int hashCode() {
+            return Objects.hash(fieldName);
+        }
+    
+        @Override
+        public String toString() {
+            return Objects.toString(fieldName);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/4c8403c3/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageProperty.java
----------------------------------------------------------------------
diff --git 
a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageProperty.java
 
b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageProperty.java
deleted file mode 100644
index 0e230d4..0000000
--- 
a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageProperty.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-package org.apache.james.jmap.model;
-
-import java.util.Arrays;
-import java.util.stream.Stream;
-
-import com.google.common.base.Preconditions;
-
-public enum MessageProperty implements Property {
-
-    id("id"),
-    blobId("blobId"),
-    threadId("threadId"),
-    mailboxIds("mailboxIds"),
-    inReplyToMessageId("inReplyToMessageId"),
-    isUnread("isUnread"),
-    isFlagged("isFlagged"),
-    isAnswered("isAnswered"),
-    isDraft("isDraft"),
-    hasAttachment("hasAttachment"),
-    headers("headers"),
-    from("from"),
-    to("to"),
-    cc("cc"),
-    bcc("bcc"),
-    replyTo("replyTo"),
-    subject("subject"),
-    date("date"),
-    size("size"),
-    preview("preview"),
-    textBody("textBody"),
-    htmlBody("htmlBody"),
-    attachments("attachments"),
-    attachedMessages("attachedMessages"),
-    body("body");
-
-    private final String property;
-
-    private MessageProperty(String property) {
-        this.property = property;
-    }
-
-    @Override
-    public String asFieldName() {
-        return property;
-    }
-
-    public static Stream<MessageProperty> find(String property) {
-        Preconditions.checkNotNull(property);
-        return Arrays.stream(values()).filter(entry -> 
entry.property.equals(property));
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/4c8403c3/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java
----------------------------------------------------------------------
diff --git 
a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java
 
b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java
index 5974697..3ba78c5 100644
--- 
a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java
+++ 
b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java
@@ -30,6 +30,7 @@ import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import org.apache.commons.lang.NotImplementedException;
 import org.apache.james.jmap.model.ClientId;
@@ -37,7 +38,7 @@ import org.apache.james.jmap.model.GetMessagesRequest;
 import org.apache.james.jmap.model.GetMessagesResponse;
 import org.apache.james.jmap.model.Message;
 import org.apache.james.jmap.model.MessageId;
-import org.apache.james.jmap.model.MessageProperty;
+import org.apache.james.jmap.model.MessageProperties.MessageProperty;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MessageManager;
 import org.apache.james.mailbox.acl.SimpleGroupMembershipResolver;
@@ -57,6 +58,8 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
+import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
 import com.google.common.base.Charsets;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Sets;
@@ -211,10 +214,13 @@ public class GetMessagesMethodTest {
                 .build();
 
         GetMessagesMethod<InMemoryId> testee = new 
GetMessagesMethod<>(mailboxSessionMapperFactory, mailboxSessionMapperFactory);
-        List<JmapResponse> result = testee.process(request, clientId, 
session).collect(Collectors.toList());
+        Stream<JmapResponse> result = testee.process(request, clientId, 
session);
 
-        assertThat(result).hasSize(1);
-        assertThat(result.get(0).getProperties()).isEmpty();
+        assertThat(result).hasSize(1)
+            .extracting(JmapResponse::getProperties)
+            .flatExtracting(Optional::get)
+            .asList()
+            .containsOnlyElementsOf(MessageProperty.allOutputProperties());
     }
 
     @Test
@@ -294,7 +300,7 @@ public class GetMessagesMethodTest {
     }
     
     @Test
-    public void 
processShouldReturnAPreconfiguredObjectMapperFilteringHeaders() throws 
Exception {
+    public void 
processShouldReturnPropertyFilterWhenFilteringHeadersRequested() throws 
Exception {
         MessageManager inbox = mailboxManager.getMailbox(inboxPath, session);
         Date now = new Date();
         ByteArrayInputStream message1Content = new 
ByteArrayInputStream(("From: u...@domain.tld\r\n"
@@ -315,8 +321,9 @@ public class GetMessagesMethodTest {
             .hasSize(1)
             .extracting(JmapResponse::getFilterProvider)
             .are(new Condition<>(Optional::isPresent, "present"));
+        SimpleFilterProvider actualFilterProvider = 
result.get(0).getFilterProvider().get();
         ObjectMapper objectMapper = new ObjectMapper();
-        
objectMapper.setFilterProvider(result.get(0).getFilterProvider().get());
+        
objectMapper.setFilterProvider(actualFilterProvider.setDefaultFilter(SimpleBeanPropertyFilter.serializeAll()));
         String response = 
objectMapper.writer().writeValueAsString(result.get(0));
         assertThat(JsonPath.parse(response).<Map<String, 
String>>read("$.response.list[0].headers")).containsOnly(MapEntry.entry("from", 
"u...@domain.tld"), MapEntry.entry("header2", "Header2Content"));
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/4c8403c3/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/GetMessagesRequestTest.java
----------------------------------------------------------------------
diff --git 
a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/GetMessagesRequestTest.java
 
b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/GetMessagesRequestTest.java
index 8cecead..2d81ba9 100644
--- 
a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/GetMessagesRequestTest.java
+++ 
b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/GetMessagesRequestTest.java
@@ -21,6 +21,8 @@ package org.apache.james.jmap.model;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
+import org.apache.james.jmap.model.MessageProperties.HeaderProperty;
+import org.apache.james.jmap.model.MessageProperties.MessageProperty;
 import org.junit.Test;
 
 import com.google.common.collect.ImmutableList;
@@ -60,8 +62,8 @@ public class GetMessagesRequestTest {
                 .ids()
                 .build();
         assertThat(result).isNotNull();
-        assertThat(result.getProperties()).isEmpty();
-        assertThat(result.getHeaderProperties()).isEmpty();
+        
assertThat(result.getProperties().getOptionalMessageProperties()).isEmpty();
+        
assertThat(result.getProperties().getOptionalHeadersProperties()).isEmpty();
     }
 
     @Test
@@ -72,8 +74,8 @@ public class GetMessagesRequestTest {
                 .properties(ImmutableList.of())
                 .build();
         assertThat(result).isNotNull();
-        assertThat(result.getProperties()).isPresent();
-        assertThat(result.getHeaderProperties()).isPresent();
+        
assertThat(result.getProperties().getOptionalMessageProperties()).hasValue(ImmutableSet.of());
+        
assertThat(result.getProperties().getOptionalHeadersProperties()).hasValue(ImmutableSet.of());
     }
 
     @Test
@@ -84,7 +86,7 @@ public class GetMessagesRequestTest {
                 .properties(ImmutableList.of("id", "headers.subject", 
"threadId", "headers.test"))
                 .build();
         assertThat(result).isNotNull();
-        
assertThat(result.getProperties()).contains(ImmutableSet.of(MessageProperty.id, 
MessageProperty.threadId));
-        
assertThat(result.getHeaderProperties()).contains(ImmutableSet.of(MessageHeaderProperty.valueOf("headers.subject"),
 MessageHeaderProperty.valueOf("headers.test")));
+        
assertThat(result.getProperties().getOptionalMessageProperties()).hasValue(ImmutableSet.of(MessageProperty.id,
 MessageProperty.threadId));
+        
assertThat(result.getProperties().getOptionalHeadersProperties()).hasValue(ImmutableSet.of(HeaderProperty.valueOf("headers.subject"),
 HeaderProperty.valueOf("headers.test")));
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/4c8403c3/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageHeaderPropertyTest.java
----------------------------------------------------------------------
diff --git 
a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageHeaderPropertyTest.java
 
b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageHeaderPropertyTest.java
index 1c2860e..f3fdada 100644
--- 
a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageHeaderPropertyTest.java
+++ 
b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageHeaderPropertyTest.java
@@ -19,40 +19,68 @@
 package org.apache.james.jmap.model;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
+import org.apache.james.jmap.model.MessageProperties.HeaderProperty;
 import org.junit.Test;
 
 public class MessageHeaderPropertyTest {
 
-    @Test(expected=NullPointerException.class)
+    @Test
+    public void fromFieldNameShouldLowercaseFieldName() {
+        
assertThat(HeaderProperty.fromFieldName("FiElD")).isEqualTo(HeaderProperty.fromFieldName("field"));
+    }
+
+    @Test
+    public void fromFieldNameShouldThrowWhenStartWithHeaderPrefix() {
+        assertThatThrownBy(() -> 
HeaderProperty.fromFieldName("headers.FiElD")).isInstanceOf(IllegalArgumentException.class);
+    }
+
+    @Test
     public void valueOfShouldThrowWhenNull() {
-        MessageHeaderProperty.valueOf(null);
+        assertThatThrownBy(() -> 
HeaderProperty.valueOf(null)).isInstanceOf(NullPointerException.class);
     }
 
-    @Test(expected=NullPointerException.class)
+    @Test
     public void valueOfalueOfShouldThrowWhenNull() {
-        MessageHeaderProperty.valueOf(null);
+        assertThatThrownBy(() -> 
HeaderProperty.valueOf(null)).isInstanceOf(NullPointerException.class);
     }
 
     @Test
     public void valueOfShouldReturnLowerCasedProperty() {
-        MessageHeaderProperty headerProperty = 
MessageHeaderProperty.valueOf("ProP");
+        HeaderProperty headerProperty = HeaderProperty.valueOf("headers.ProP");
 
         assertThat(headerProperty.asFieldName()).isEqualTo("prop");
     }
 
     @Test
+    public void valueOfShouldThrowWhenValueIsNotHeader() {
+        assertThatThrownBy(() -> 
HeaderProperty.valueOf("ProP")).isInstanceOf(IllegalArgumentException.class);
+    }
+    
+    @Test
+    public void findShouldReturnStreamWhenValueStartsWithRightString() {
+        assertThat(HeaderProperty.find(HeaderProperty.HEADER_PROPERTY_PREFIX + 
"myvalue"))
+            
.contains(HeaderProperty.valueOf(HeaderProperty.HEADER_PROPERTY_PREFIX + 
"myvalue"));
+    }
+
+    @Test
+    public void findShouldReturnEmptyStreamWhenValueStartsWithWrongString() {
+        assertThat(HeaderProperty.find("bad value" + 
HeaderProperty.HEADER_PROPERTY_PREFIX + "myvalue")).isEmpty();
+    }
+    
+    @Test
     public void equalsShouldBeTrueWhenIdenticalProperties() {
-        
assertThat(MessageHeaderProperty.valueOf("prop")).isEqualTo(MessageHeaderProperty.valueOf("prop"));
+        
assertThat(HeaderProperty.valueOf("headers.prop")).isEqualTo(HeaderProperty.valueOf("headers.prop"));
     }
 
     @Test
     public void equalsShouldBeFalseWhenDifferentProperties() {
-        
assertThat(MessageHeaderProperty.valueOf("prop")).isNotEqualTo(MessageHeaderProperty.valueOf("other"));
+        
assertThat(HeaderProperty.valueOf("headers.prop")).isNotEqualTo(HeaderProperty.valueOf("headers.other"));
     }
 
     @Test
     public void equalsShouldBeTrueWhenDifferentCaseProperties() {
-        
assertThat(MessageHeaderProperty.valueOf("prOP")).isEqualTo(MessageHeaderProperty.valueOf("PRop"));
+        
assertThat(HeaderProperty.valueOf("headers.prOP")).isEqualTo(HeaderProperty.valueOf("headers.PRop"));
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/4c8403c3/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessagePropertiesTest.java
----------------------------------------------------------------------
diff --git 
a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessagePropertiesTest.java
 
b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessagePropertiesTest.java
new file mode 100644
index 0000000..f6eb239
--- /dev/null
+++ 
b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessagePropertiesTest.java
@@ -0,0 +1,82 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.jmap.model;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.Optional;
+
+import org.apache.james.jmap.model.MessageProperties.MessageProperty;
+import org.apache.james.jmap.model.MessageProperties.HeaderProperty;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableSet;
+
+public class MessagePropertiesTest {
+
+    @Test
+    public void toOutputPropertiesShouldReturnAllMessagePropertiesWhenAbsent() 
{
+        MessageProperties actual = new 
MessageProperties(Optional.empty()).toOutputProperties();
+        
assertThat(actual.getOptionalMessageProperties()).hasValue(MessageProperty.allOutputProperties());
+    }
+    
+    @Test
+    public void 
toOutputPropertiesShouldReturnEmptyHeaderPropertiesWhenAbsent() {
+        MessageProperties actual = new 
MessageProperties(Optional.empty()).toOutputProperties();
+        assertThat(actual.getOptionalHeadersProperties()).isEmpty();
+    }
+
+    @Test
+    public void toOutputPropertiesShouldReturnTextBodyWhenBodyRequested() {
+        MessageProperties actual = new 
MessageProperties(Optional.of(ImmutableSet.of("body"))).toOutputProperties();
+        assertThat(actual.getOptionalMessageProperties())
+            .hasValueSatisfying(value -> 
+                
assertThat(value).contains(MessageProperty.textBody).doesNotContain(MessageProperty.body));
+    }
+    
+    @Test
+    public void 
toOutputPropertiesShouldReturnMandatoryPropertiesWhenEmptyRequest() {
+        MessageProperties actual = new 
MessageProperties(Optional.of(ImmutableSet.of())).toOutputProperties();
+        assertThat(actual.getOptionalMessageProperties())
+            .hasValue(ImmutableSet.of(MessageProperty.id, 
MessageProperty.threadId, MessageProperty.mailboxIds));
+    }
+
+    @Test
+    public void 
toOutputPropertiesShouldReturnAllHeadersWhenHeadersAndIndividualHeadersRequested()
 {
+        MessageProperties actual = new MessageProperties(
+            Optional.of(ImmutableSet.of("headers.X-Spam-Score", 
"headers"))).toOutputProperties();
+        assertThat(actual.getOptionalMessageProperties()).hasValueSatisfying(
+            value -> assertThat(value).contains(MessageProperty.headers)
+        );
+        assertThat(actual.getOptionalHeadersProperties()).isEmpty();
+    }
+
+    @Test
+    public void 
toOutputPropertiesShouldReturnHeadersMessagePropertyWhenIndividualHeadersRequested()
 {
+        MessageProperties actual = new MessageProperties(
+            
Optional.of(ImmutableSet.of("headers.X-Spam-Score"))).toOutputProperties();
+        assertThat(actual.getOptionalMessageProperties()).hasValueSatisfying(
+            value -> assertThat(value).contains(MessageProperty.headers)
+        );
+        assertThat(actual.getOptionalHeadersProperties()).hasValueSatisfying(
+            value -> 
assertThat(value).contains(HeaderProperty.fromFieldName("x-spam-score"))
+        );
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/4c8403c3/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessagePropertyTest.java
----------------------------------------------------------------------
diff --git 
a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessagePropertyTest.java
 
b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessagePropertyTest.java
index f9157f4..731a66e 100644
--- 
a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessagePropertyTest.java
+++ 
b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessagePropertyTest.java
@@ -18,9 +18,10 @@
  ****************************************************************/
 package org.apache.james.jmap.model;
 
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
+import org.apache.james.jmap.model.MessageProperties.MessageProperty;
 import org.junit.Test;
 
 public class MessagePropertyTest {


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org
For additional commands, e-mail: server-dev-h...@james.apache.org

Reply via email to