Repository: EnMasseProject/enmasse
Pull request #2109 (2018-12-11 14:01:58)

[#2107] Use the builder and common fabric8 base classes for User
This change refactors the "User" model to use the generated builders
instead of custom ones. Re-use the fabric8 ObjectMeta definition. And
simplifies the JSON parts a bit.

This also prepares the way to store ownerReferences. I have an initial version for that with the `MessagingUser`, which seems to work with the IoT project.

ctron: > I would prefer to just drop the VirtualBeanPropertyWriter and CustomResource stuff. Since we know upfront what resources we have up front, having a static initializer like in AdminCrd is less magic and easier to read IMO.

I know there is a bit of magic included. But right now the information is repeated and spread all over the place. A future change might easily break things. This way you only have one location where stuff is happening and one location where the information is.

If your concern is performance, then I think this can be improved to resorting to a bit of static information, like the `CRD` constant.
ctron: I pushed a commit which removes the annotation processing, but still tries to keep all information and logic in one place. Adding a `UserCrd` in the process, just to show how this would work.

if this is ok, then I would start working on refactoring the other parts as well, creating a common `model` artifact.
lulf: Excellent work @ctron , thanks! By 'core' do you mean Address and AddressSpace? They were written before fabric8 was used, so they are using the 'Builder' style and with explicit serializer/deserializer classes for the 'v1' version. IMO they should be converted to the same type of model-mixed-with-serialization as the other types, but take care to about the nitty gritty details on the Serializer/Deserializer classes which handles some backward compatibility cases.

I'm fine with leaving those as is for now if you want follow up that work in a second PR.
ctron: Thank you! I saw there seems to be some glitch in the current PR, both CIs fail. I will fix that. And then I would say it would be a good point to merge this indeed.

I would still need the `ObjectMetadata` in the `AddressSpace` as well. So I will need to work on that. However I am not sure if I will manage to get this "merge ready" by the end of tomorrow. After that I will be out of office until early next year.

I would prefer to finish up this PR, and then get it merged. So I can start working on the rest, when I come back from vacation.
ctron: I rebased after the merge of e069e4d41abe5504b4c4dfc5e0477ff55619a37f
ctron: Rebased after the merge of #2113 

Patch:
diff --git a/address-model-lib/README.md b/address-model-lib/README.md
deleted file mode 100644
index c4c0f7240..000000000
--- a/address-model-lib/README.md
+++ /dev/null
@@ -1,1 +0,0 @@
-The address-model library contains a Java object model of the EnMasse addressing model
diff --git a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/AddressPlanList.java b/address-model-lib/src/main/java/io/enmasse/admin/model/v1/AddressPlanList.java
deleted file mode 100644
index b9e478137..000000000
--- a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/AddressPlanList.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2018, EnMasse authors.
- * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
- */
-package io.enmasse.admin.model.v1;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.JsonDeserializer;
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import io.fabric8.kubernetes.api.model.KubernetesResource;
-import io.fabric8.kubernetes.api.model.KubernetesResourceList;
-import io.fabric8.kubernetes.api.model.ListMeta;
-
-import java.util.Collections;
-import java.util.List;
-
-@JsonDeserialize(
-    using = JsonDeserializer.None.class
-)
-@JsonInclude(JsonInclude.Include.NON_NULL)
-public class AddressPlanList implements KubernetesResource<AddressPlan>, KubernetesResourceList<AddressPlan> {
-    private static final long serialVersionUID = 1L;
-
-    private String apiVersion;
-    private String kind;
-    private ListMeta metadata;
-    private final List<AddressPlan> items;
-
-    @JsonCreator
-    public AddressPlanList(@JsonProperty("items") List<AddressPlan> items) {
-        this.items = items;
-    }
-
-    @Override
-    public ListMeta getMetadata() {
-        return metadata;
-    }
-
-    @Override
-    public List<AddressPlan> getItems() {
-        return Collections.unmodifiableList(items);
-    }
-
-    public void setMetadata(ListMeta metadata) {
-        this.metadata = metadata;
-    }
-
-    public String getApiVersion() {
-        return apiVersion;
-    }
-
-    public void setApiVersion(String apiVersion) {
-        this.apiVersion = apiVersion;
-    }
-
-    public String getKind() {
-        return kind;
-    }
-
-    public void setKind(String kind) {
-        this.kind = kind;
-    }
-}
diff --git a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/AddressSpacePlanList.java b/address-model-lib/src/main/java/io/enmasse/admin/model/v1/AddressSpacePlanList.java
deleted file mode 100644
index 7729c99a7..000000000
--- a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/AddressSpacePlanList.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2018, EnMasse authors.
- * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
- */
-package io.enmasse.admin.model.v1;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.JsonDeserializer;
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import io.fabric8.kubernetes.api.model.*;
-
-import java.util.Collections;
-import java.util.List;
-
-@JsonDeserialize(
-    using = JsonDeserializer.None.class
-)
-@JsonInclude(JsonInclude.Include.NON_NULL)
-public class AddressSpacePlanList implements KubernetesResource<AddressSpacePlan>, KubernetesResourceList<AddressSpacePlan> {
-    private static final long serialVersionUID = 1L;
-
-    private String apiVersion;
-    private String kind;
-    private ListMeta metadata;
-    private final List<AddressSpacePlan> items;
-
-    @JsonCreator
-    public AddressSpacePlanList(@JsonProperty("items") List<AddressSpacePlan> items) {
-        this.items = items;
-    }
-
-    @Override
-    public ListMeta getMetadata() {
-        return metadata;
-    }
-
-    @Override
-    public List<AddressSpacePlan> getItems() {
-        return Collections.unmodifiableList(items);
-    }
-
-    public void setMetadata(ListMeta metadata) {
-        this.metadata = metadata;
-    }
-
-    public String getApiVersion() {
-        return apiVersion;
-    }
-
-    public void setApiVersion(String apiVersion) {
-        this.apiVersion = apiVersion;
-    }
-
-    public String getKind() {
-        return kind;
-    }
-
-    public void setKind(String kind) {
-        this.kind = kind;
-    }
-
-    @Override
-    public String toString() {
-        return "{metadata=" + metadata + "," +
-                "items=" + items + "}";
-    }
-}
diff --git a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/AdminCrd.java b/address-model-lib/src/main/java/io/enmasse/admin/model/v1/AdminCrd.java
deleted file mode 100644
index b6a3bd3f0..000000000
--- a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/AdminCrd.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2018, EnMasse authors.
- * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
- */
-package io.enmasse.admin.model.v1;
-
-import io.fabric8.kubernetes.api.model.apiextensions.CustomResourceDefinition;
-import io.fabric8.kubernetes.api.model.apiextensions.CustomResourceDefinitionBuilder;
-import io.fabric8.kubernetes.internal.KubernetesDeserializer;
-
-public class AdminCrd {
-
-    public static void registerCustomCrds() {
-        KubernetesDeserializer.registerCustomKind("admin.enmasse.io/v1alpha1", AddressSpacePlan.ADDRESS_SPACE_PLAN, AddressSpacePlan.class);
-        KubernetesDeserializer.registerCustomKind("admin.enmasse.io/v1alpha1", AddressPlan.ADDRESS_PLAN, AddressPlan.class);
-        KubernetesDeserializer.registerCustomKind("admin.enmasse.io/v1alpha1", StandardInfraConfig.STANDARD_INFRA_CONFIG, StandardInfraConfig.class);
-        KubernetesDeserializer.registerCustomKind("admin.enmasse.io/v1alpha1", BrokeredInfraConfig.BROKERED_INFRA_CONFIG, BrokeredInfraConfig.class);
-    }
-
-    public static CustomResourceDefinition addressspaceplans() {
-        return createCrd(AddressSpacePlan.ADDRESS_SPACE_PLAN);
-    }
-
-    public static CustomResourceDefinition addressplans() {
-        return createCrd(AddressPlan.ADDRESS_PLAN);
-    }
-
-    public static CustomResourceDefinition brokeredinfraconfigs() {
-        return createCrd(BrokeredInfraConfig.BROKERED_INFRA_CONFIG);
-    }
-
-    public static CustomResourceDefinition standardinfraconfigs() {
-        return createCrd(StandardInfraConfig.STANDARD_INFRA_CONFIG);
-    }
-
-    private static CustomResourceDefinition createCrd(String kind) {
-        String singular = kind.toLowerCase();
-        String listKind = kind + "List";
-        String plural = singular + "s";
-        return new CustomResourceDefinitionBuilder()
-                .editOrNewMetadata()
-                .withName(plural + ".admin.enmassse.io")
-                .addToLabels("app", "enmasse")
-                .endMetadata()
-                .editOrNewSpec()
-                .withGroup("admin.enmasse.io")
-                .withVersion("v1alpha1")
-                .withScope("Namespaced")
-                .editOrNewNames()
-                .withKind(kind)
-                .withListKind(listKind)
-                .withPlural(plural)
-                .withSingular(singular)
-                .endNames()
-                .endSpec()
-                .build();
-    }
-}
diff --git a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfig.java b/address-model-lib/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfig.java
deleted file mode 100644
index 316c6e5e6..000000000
--- a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfig.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright 2018, EnMasse authors.
- * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
- */
-package io.enmasse.admin.model.v1;
-
-import com.fasterxml.jackson.annotation.*;
-import com.fasterxml.jackson.databind.JsonDeserializer;
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import io.fabric8.kubernetes.api.model.Doneable;
-import io.fabric8.kubernetes.api.model.ObjectMeta;
-import io.sundr.builder.annotations.Buildable;
-import io.sundr.builder.annotations.Inline;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-
-@JsonDeserialize(
-        using = JsonDeserializer.None.class
-)
-@Buildable(
-        editableEnabled = false,
-        generateBuilderPackage = false,
-        builderPackage = "io.fabric8.kubernetes.api.builder",
-        inline = @Inline(type = Doneable.class, prefix = "Doneable", value = "done")
-)
-@JsonPropertyOrder({"apiVersion", "kind", "metadata", "spec"})
-@JsonInclude(JsonInclude.Include.NON_NULL)
-public class BrokeredInfraConfig implements InfraConfig {
-
-    public static final String BROKERED_INFRA_CONFIG = "BrokeredInfraConfig";
-    private String apiVersion = "admin.enmasse.io/v1alpha1";
-    private String kind = BROKERED_INFRA_CONFIG;
-    private ObjectMeta metadata;
-    private final BrokeredInfraConfigSpec spec;
-
-    private Map<String, Object> additionalProperties = new HashMap<>(0);
-
-    @JsonCreator
-    public BrokeredInfraConfig(@JsonProperty("metadata") ObjectMeta metadata,
-                               @JsonProperty("spec") BrokeredInfraConfigSpec spec) {
-        this.metadata = metadata;
-        this.spec = spec;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-        BrokeredInfraConfig that = (BrokeredInfraConfig) o;
-        return Objects.equals(metadata, that.metadata) &&
-                Objects.equals(spec, that.spec);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(metadata, spec);
-    }
-
-    @Override
-    public String toString() {
-        return "BrokeredInfraConfig{" +
-                "metadata=" + metadata +
-                ", spec=" + spec + "}";
-    }
-
-    public ObjectMeta getMetadata() {
-        return metadata;
-    }
-
-    public BrokeredInfraConfigSpec getSpec() {
-        return spec;
-    }
-
-    public void setMetadata(ObjectMeta metadata) {
-        this.metadata = metadata;
-    }
-
-    @Override
-    public String getApiVersion() {
-        return apiVersion;
-    }
-
-    @Override
-    public void setApiVersion(String apiVersion) {
-        this.apiVersion = apiVersion;
-    }
-
-    @Override
-    public String getKind() {
-        return kind;
-    }
-
-    public void setKind(String kind) {
-        this.kind = kind;
-    }
-
-    @JsonAnyGetter
-    public Map<String, Object> getAdditionalProperties() {
-        return this.additionalProperties;
-    }
-
-    @JsonAnySetter
-    public void setAdditionalProperty(String name, Object value) {
-        this.additionalProperties.put(name, value);
-    }
-
-    @Override
-    @JsonIgnore
-    public String getVersion() {
-        return spec.getVersion();
-    }
-
-    @Override
-    @JsonIgnore
-    public NetworkPolicy getNetworkPolicy() {
-        return spec.getNetworkPolicy();
-    }
-
-    @Override
-    @JsonIgnore
-    public boolean getUpdatePersistentVolumeClaim() {
-        return spec.getBroker().getUpdatePersistentVolumeClaim() != null ? spec.getBroker().getUpdatePersistentVolumeClaim() : false;
-    }
-}
diff --git a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigList.java b/address-model-lib/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigList.java
deleted file mode 100644
index 5b59ada65..000000000
--- a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigList.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2018, EnMasse authors.
- * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
- */
-package io.enmasse.admin.model.v1;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.JsonDeserializer;
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import io.fabric8.kubernetes.api.model.KubernetesResource;
-import io.fabric8.kubernetes.api.model.KubernetesResourceList;
-import io.fabric8.kubernetes.api.model.ListMeta;
-
-import java.util.Collections;
-import java.util.List;
-
-@JsonDeserialize(
-    using = JsonDeserializer.None.class
-)
-@JsonInclude(JsonInclude.Include.NON_NULL)
-public class BrokeredInfraConfigList implements KubernetesResource<BrokeredInfraConfig>, KubernetesResourceList<BrokeredInfraConfig> {
-    private static final long serialVersionUID = 1L;
-
-    private String apiVersion;
-    private String kind;
-    private ListMeta metadata;
-    private final List<BrokeredInfraConfig> items;
-
-    @JsonCreator
-    public BrokeredInfraConfigList(@JsonProperty("items") List<BrokeredInfraConfig> items) {
-        this.items = items;
-    }
-
-    @Override
-    public ListMeta getMetadata() {
-        return metadata;
-    }
-
-    @Override
-    public List<BrokeredInfraConfig> getItems() {
-        return Collections.unmodifiableList(items);
-    }
-
-    public void setMetadata(ListMeta metadata) {
-        this.metadata = metadata;
-    }
-
-    public String getApiVersion() {
-        return apiVersion;
-    }
-
-    public void setApiVersion(String apiVersion) {
-        this.apiVersion = apiVersion;
-    }
-
-    public String getKind() {
-        return kind;
-    }
-
-    public void setKind(String kind) {
-        this.kind = kind;
-    }
-}
diff --git a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfig.java b/address-model-lib/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfig.java
deleted file mode 100644
index 83f57007d..000000000
--- a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfig.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright 2018, EnMasse authors.
- * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
- */
-package io.enmasse.admin.model.v1;
-
-import com.fasterxml.jackson.annotation.*;
-import com.fasterxml.jackson.databind.JsonDeserializer;
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import io.fabric8.kubernetes.api.model.Doneable;
-import io.fabric8.kubernetes.api.model.ObjectMeta;
-import io.sundr.builder.annotations.Buildable;
-import io.sundr.builder.annotations.Inline;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-
-@JsonDeserialize(
-        using = JsonDeserializer.None.class
-)
-@Buildable(
-        editableEnabled = false,
-        generateBuilderPackage = false,
-        builderPackage = "io.fabric8.kubernetes.api.builder",
-        inline = @Inline(type = Doneable.class, prefix = "Doneable", value = "done")
-)
-@JsonPropertyOrder({"apiVersion", "kind", "metadata", "spec"})
-@JsonInclude(JsonInclude.Include.NON_NULL)
-public class StandardInfraConfig implements InfraConfig {
-    public static final String STANDARD_INFRA_CONFIG = "StandardInfraConfig";
-    private String apiVersion = "admin.enmasse.io/v1alpha1";
-    private String kind = STANDARD_INFRA_CONFIG;
-
-    private ObjectMeta metadata;
-    private final StandardInfraConfigSpec spec;
-
-    private Map<String, Object> additionalProperties = new HashMap<>(0);
-
-    @JsonCreator
-    public StandardInfraConfig(@JsonProperty("metadata") ObjectMeta metadata,
-                               @JsonProperty("spec") StandardInfraConfigSpec spec) {
-        this.metadata = metadata;
-        this.spec = spec;
-    }
-
-    public ObjectMeta getMetadata() {
-        return metadata;
-    }
-
-    public StandardInfraConfigSpec getSpec() {
-        return spec;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-        StandardInfraConfig that = (StandardInfraConfig) o;
-        return Objects.equals(metadata, that.metadata) &&
-                Objects.equals(spec, that.spec);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(metadata, spec);
-    }
-
-    @Override
-    public String toString() {
-        return "StandardInfraConfig{" +
-                "metadata=" + metadata +
-                ", spec=" + spec + "}";
-    }
-
-    @Override
-    public String getApiVersion() {
-        return apiVersion;
-    }
-
-    @Override
-    public void setApiVersion(String apiVersion) {
-        this.apiVersion = apiVersion;
-    }
-
-    @Override
-    public String getKind() {
-        return kind;
-    }
-
-    public void setKind(String kind) {
-        this.kind = kind;
-    }
-
-    @Override
-    public void setMetadata(ObjectMeta metadata) {
-        this.metadata = metadata;
-    }
-
-    @JsonAnyGetter
-    public Map<String, Object> getAdditionalProperties() {
-        return this.additionalProperties;
-    }
-
-    @JsonAnySetter
-    public void setAdditionalProperty(String name, Object value) {
-        this.additionalProperties.put(name, value);
-    }
-
-    @Override
-    @JsonIgnore
-    public String getVersion() {
-        return spec.getVersion();
-    }
-
-    @Override
-    @JsonIgnore
-    public NetworkPolicy getNetworkPolicy() {
-        return spec.getNetworkPolicy();
-    }
-
-    @Override
-    @JsonIgnore
-    public boolean getUpdatePersistentVolumeClaim() {
-        return spec.getBroker().getUpdatePersistentVolumeClaim() != null ? spec.getBroker().getUpdatePersistentVolumeClaim() : false;
-    }
-}
diff --git a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigList.java b/address-model-lib/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigList.java
deleted file mode 100644
index d24f56412..000000000
--- a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigList.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2018, EnMasse authors.
- * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
- */
-package io.enmasse.admin.model.v1;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.JsonDeserializer;
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import io.fabric8.kubernetes.api.model.KubernetesResource;
-import io.fabric8.kubernetes.api.model.KubernetesResourceList;
-import io.fabric8.kubernetes.api.model.ListMeta;
-
-import java.util.Collections;
-import java.util.List;
-
-@JsonDeserialize(
-    using = JsonDeserializer.None.class
-)
-@JsonInclude(JsonInclude.Include.NON_NULL)
-public class StandardInfraConfigList implements KubernetesResource<StandardInfraConfig>, KubernetesResourceList<StandardInfraConfig> {
-    private static final long serialVersionUID = 1L;
-
-    private String apiVersion;
-    private String kind;
-    private ListMeta metadata;
-    private final List<StandardInfraConfig> items;
-
-    @JsonCreator
-    public StandardInfraConfigList(@JsonProperty("items") List<StandardInfraConfig> items) {
-        this.items = items;
-    }
-
-    @Override
-    public ListMeta getMetadata() {
-        return metadata;
-    }
-
-    @Override
-    public List<StandardInfraConfig> getItems() {
-        return Collections.unmodifiableList(items);
-    }
-
-    public void setMetadata(ListMeta metadata) {
-        this.metadata = metadata;
-    }
-
-    public String getApiVersion() {
-        return apiVersion;
-    }
-
-    public void setApiVersion(String apiVersion) {
-        this.apiVersion = apiVersion;
-    }
-
-    public String getKind() {
-        return kind;
-    }
-
-    public void setKind(String kind) {
-        this.kind = kind;
-    }
-}
diff --git a/address-space-controller/pom.xml b/address-space-controller/pom.xml
index 8912f86aa..a6ee3f680 100644
--- a/address-space-controller/pom.xml
+++ b/address-space-controller/pom.xml
@@ -9,11 +9,6 @@
   <modelVersion>4.0.0</modelVersion>
   <artifactId>address-space-controller</artifactId>
   <dependencies>
-    <dependency>
-      <groupId>io.enmasse</groupId>
-      <artifactId>address-model-lib</artifactId>
-      <scope>compile</scope>
-    </dependency>
     <dependency>
       <groupId>io.enmasse</groupId>
       <artifactId>metrics-api</artifactId>
@@ -21,8 +16,7 @@
     </dependency>
     <dependency>
       <groupId>io.enmasse</groupId>
-      <artifactId>user-api</artifactId>
-      <scope>compile</scope>
+      <artifactId>api-model</artifactId>
     </dependency>
     <dependency>
       <groupId>io.enmasse</groupId>
diff --git a/address-space-controller/src/main/java/io/enmasse/controller/AddressSpaceController.java b/address-space-controller/src/main/java/io/enmasse/controller/AddressSpaceController.java
index 5b5174406..dcad2862f 100644
--- a/address-space-controller/src/main/java/io/enmasse/controller/AddressSpaceController.java
+++ b/address-space-controller/src/main/java/io/enmasse/controller/AddressSpaceController.java
@@ -133,21 +133,21 @@ public class AddressSpaceController {
     private void configureDefaultResources(NamespacedOpenShiftClient client, File resourcesDir) {
         String namespace = client.getNamespace();
         KubeResourceApplier.applyIfDifferent(new File(resourcesDir, "brokeredinfraconfigs"),
-                client.customResources(AdminCrd.brokeredinfraconfigs(), BrokeredInfraConfig.class, BrokeredInfraConfigList.class, DoneableBrokeredInfraConfig.class).inNamespace(namespace),
+                client.customResources(AdminCrd.brokeredInfraConfigs(), BrokeredInfraConfig.class, BrokeredInfraConfigList.class, DoneableBrokeredInfraConfig.class).inNamespace(namespace),
                 BrokeredInfraConfig.class,
                 Comparator.comparing(BrokeredInfraConfig::getVersion));
 
         KubeResourceApplier.applyIfDifferent(new File(resourcesDir, "standardinfraconfigs"),
-                client.customResources(AdminCrd.standardinfraconfigs(), StandardInfraConfig.class, StandardInfraConfigList.class, DoneableStandardInfraConfig.class).inNamespace(namespace),
+                client.customResources(AdminCrd.standardInfraConfigs(), StandardInfraConfig.class, StandardInfraConfigList.class, DoneableStandardInfraConfig.class).inNamespace(namespace),
                 StandardInfraConfig.class,
                 Comparator.comparing(StandardInfraConfig::getVersion));
 
         KubeResourceApplier.createIfNoneExists(new File(resourcesDir, "addressplans"),
-                client.customResources(AdminCrd.addressplans(), AddressPlan.class, AddressPlanList.class, DoneableAddressPlan.class).inNamespace(namespace),
+                client.customResources(AdminCrd.addressPlans(), AddressPlan.class, AddressPlanList.class, DoneableAddressPlan.class).inNamespace(namespace),
                 AddressPlan.class);
 
         KubeResourceApplier.createIfNoneExists(new File(resourcesDir, "addressspaceplans"),
-                client.customResources(AdminCrd.addressspaceplans(), AddressSpacePlan.class, AddressSpacePlanList.class, DoneableAddressSpacePlan.class).inNamespace(namespace),
+                client.customResources(AdminCrd.addressSpacePlans(), AddressSpacePlan.class, AddressSpacePlanList.class, DoneableAddressSpacePlan.class).inNamespace(namespace),
                 AddressSpacePlan.class);
     }
 
diff --git a/address-space-controller/src/main/java/io/enmasse/controller/CertProviderFactory.java b/address-space-controller/src/main/java/io/enmasse/controller/CertProviderFactory.java
index b2bdfb3a0..ff317ea52 100644
--- a/address-space-controller/src/main/java/io/enmasse/controller/CertProviderFactory.java
+++ b/address-space-controller/src/main/java/io/enmasse/controller/CertProviderFactory.java
@@ -4,7 +4,6 @@
  */
 package io.enmasse.controller;
 
-import io.enmasse.address.model.CertSpec;
 import io.enmasse.controller.auth.CertProvider;
 
 public interface CertProviderFactory {
diff --git a/address-space-controller/src/main/java/io/enmasse/controller/InfraResourceFactory.java b/address-space-controller/src/main/java/io/enmasse/controller/InfraResourceFactory.java
index ee63a0d73..7d574035e 100644
--- a/address-space-controller/src/main/java/io/enmasse/controller/InfraResourceFactory.java
+++ b/address-space-controller/src/main/java/io/enmasse/controller/InfraResourceFactory.java
@@ -5,9 +5,7 @@
 package io.enmasse.controller;
 
 import io.enmasse.address.model.AddressSpace;
-import io.enmasse.admin.model.v1.BrokeredInfraConfig;
 import io.enmasse.admin.model.v1.InfraConfig;
-import io.enmasse.admin.model.v1.StandardInfraConfig;
 import io.fabric8.kubernetes.api.model.HasMetadata;
 
 import java.util.List;
diff --git a/address-space-controller/src/main/java/io/enmasse/controller/ServiceHelper.java b/address-space-controller/src/main/java/io/enmasse/controller/ServiceHelper.java
index 236fc2852..c212266cc 100644
--- a/address-space-controller/src/main/java/io/enmasse/controller/ServiceHelper.java
+++ b/address-space-controller/src/main/java/io/enmasse/controller/ServiceHelper.java
@@ -8,7 +8,6 @@ import io.enmasse.config.AnnotationKeys;
 import io.fabric8.kubernetes.api.model.Service;
 
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 public class ServiceHelper {
diff --git a/address-space-controller/src/main/java/io/enmasse/controller/auth/CertBundleCertProvider.java b/address-space-controller/src/main/java/io/enmasse/controller/auth/CertBundleCertProvider.java
index 1bc15a536..83663dbe4 100644
--- a/address-space-controller/src/main/java/io/enmasse/controller/auth/CertBundleCertProvider.java
+++ b/address-space-controller/src/main/java/io/enmasse/controller/auth/CertBundleCertProvider.java
@@ -13,8 +13,6 @@ import io.fabric8.openshift.client.OpenShiftClient;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.nio.charset.StandardCharsets;
-import java.util.Base64;
 import java.util.HashMap;
 import java.util.Map;
 
diff --git a/address-space-controller/src/main/java/io/enmasse/controller/auth/CertManager.java b/address-space-controller/src/main/java/io/enmasse/controller/auth/CertManager.java
index 59751a992..9c5013897 100644
--- a/address-space-controller/src/main/java/io/enmasse/controller/auth/CertManager.java
+++ b/address-space-controller/src/main/java/io/enmasse/controller/auth/CertManager.java
@@ -8,7 +8,6 @@ import io.fabric8.kubernetes.api.model.Secret;
 
 import java.util.Collection;
 import java.util.Map;
-import java.util.Set;
 
 /**
  * Interface for certificate managers
diff --git a/address-space-controller/src/main/java/io/enmasse/controller/auth/CertProvider.java b/address-space-controller/src/main/java/io/enmasse/controller/auth/CertProvider.java
index eada2a64e..406fadc57 100644
--- a/address-space-controller/src/main/java/io/enmasse/controller/auth/CertProvider.java
+++ b/address-space-controller/src/main/java/io/enmasse/controller/auth/CertProvider.java
@@ -5,11 +5,6 @@
 package io.enmasse.controller.auth;
 
 import io.enmasse.address.model.AddressSpace;
-import io.enmasse.address.model.EndpointSpec;
-import io.fabric8.kubernetes.api.model.Secret;
-
-import java.util.Collection;
-import java.util.Set;
 
 public interface CertProvider {
     void provideCert(AddressSpace addressSpace, EndpointInfo endpointInfo);
diff --git a/address-space-controller/src/main/java/io/enmasse/controller/common/KubernetesHelper.java b/address-space-controller/src/main/java/io/enmasse/controller/common/KubernetesHelper.java
index b903fa247..858cc1e96 100644
--- a/address-space-controller/src/main/java/io/enmasse/controller/common/KubernetesHelper.java
+++ b/address-space-controller/src/main/java/io/enmasse/controller/common/KubernetesHelper.java
@@ -158,7 +158,7 @@ public class KubernetesHelper implements Kubernetes {
         return client.services().inNamespace(namespace).withName(KubeUtil.getAddressSpaceServiceName("messaging", addressSpace)).get() != null;
     }
 
-    private Map doRawHttpRequest(String path, String method, Map body, boolean errorOk) {
+    private Map<?,?> doRawHttpRequest(String path, String method, Map<?,?> body, boolean errorOk) {
         OkHttpClient httpClient = client.adapt(OkHttpClient.class);
 
         try {
diff --git a/api-common/pom.xml b/api-common/pom.xml
index ad8f03e7c..31e20a589 100644
--- a/api-common/pom.xml
+++ b/api-common/pom.xml
@@ -11,13 +11,7 @@
   <dependencies>
     <dependency>
       <groupId>io.enmasse</groupId>
-      <artifactId>address-model-lib</artifactId>
-      <scope>compile</scope>
-    </dependency>
-    <dependency>
-      <groupId>io.enmasse</groupId>
-      <artifactId>user-api</artifactId>
-      <scope>compile</scope>
+      <artifactId>api-model</artifactId>
     </dependency>
     <dependency>
       <groupId>io.enmasse</groupId>
diff --git a/address-model-lib/pom.xml b/api-model/pom.xml
similarity index 87%
rename from address-model-lib/pom.xml
rename to api-model/pom.xml
index 0d39a8569..5094cf841 100644
--- a/address-model-lib/pom.xml
+++ b/api-model/pom.xml
@@ -7,8 +7,7 @@
     <version>0.25-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
-  <groupId>io.enmasse</groupId>
-  <artifactId>address-model-lib</artifactId>
+  <artifactId>api-model</artifactId>
   <dependencies>
     <dependency>
       <groupId>io.fabric8</groupId>
@@ -22,17 +21,10 @@
     <dependency>
       <groupId>com.fasterxml.jackson.core</groupId>
       <artifactId>jackson-core</artifactId>
-      <scope>compile</scope>
     </dependency>
     <dependency>
       <groupId>com.fasterxml.jackson.core</groupId>
       <artifactId>jackson-databind</artifactId>
-      <scope>compile</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.slf4j</groupId>
-      <artifactId>slf4j-api</artifactId>
-      <scope>compile</scope>
     </dependency>
     <dependency>
       <groupId>org.junit.jupiter</groupId>
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/Address.java b/api-model/src/main/java/io/enmasse/address/model/Address.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/Address.java
rename to api-model/src/main/java/io/enmasse/address/model/Address.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/AddressList.java b/api-model/src/main/java/io/enmasse/address/model/AddressList.java
similarity index 89%
rename from address-model-lib/src/main/java/io/enmasse/address/model/AddressList.java
rename to api-model/src/main/java/io/enmasse/address/model/AddressList.java
index ab448507d..38fc5d2a9 100644
--- a/address-model-lib/src/main/java/io/enmasse/address/model/AddressList.java
+++ b/api-model/src/main/java/io/enmasse/address/model/AddressList.java
@@ -12,6 +12,9 @@ import java.util.Set;
  * Type for address lists.
  */
 public class AddressList extends ArrayList<Address> {
+
+    private static final long serialVersionUID = 1L;
+
     public AddressList() {
         super();
     }
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/AddressResolver.java b/api-model/src/main/java/io/enmasse/address/model/AddressResolver.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/AddressResolver.java
rename to api-model/src/main/java/io/enmasse/address/model/AddressResolver.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/AddressSpace.java b/api-model/src/main/java/io/enmasse/address/model/AddressSpace.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/AddressSpace.java
rename to api-model/src/main/java/io/enmasse/address/model/AddressSpace.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/AddressSpaceList.java b/api-model/src/main/java/io/enmasse/address/model/AddressSpaceList.java
similarity index 90%
rename from address-model-lib/src/main/java/io/enmasse/address/model/AddressSpaceList.java
rename to api-model/src/main/java/io/enmasse/address/model/AddressSpaceList.java
index e7cbc875e..7f0a8131e 100644
--- a/address-model-lib/src/main/java/io/enmasse/address/model/AddressSpaceList.java
+++ b/api-model/src/main/java/io/enmasse/address/model/AddressSpaceList.java
@@ -12,6 +12,8 @@ import java.util.Collection;
  */
 public class AddressSpaceList extends ArrayList<AddressSpace> {
 
+    private static final long serialVersionUID = 1L;
+
     public AddressSpaceList() {
         super();
     }
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/AddressSpaceResolver.java b/api-model/src/main/java/io/enmasse/address/model/AddressSpaceResolver.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/AddressSpaceResolver.java
rename to api-model/src/main/java/io/enmasse/address/model/AddressSpaceResolver.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/AddressSpaceSchema.java b/api-model/src/main/java/io/enmasse/address/model/AddressSpaceSchema.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/AddressSpaceSchema.java
rename to api-model/src/main/java/io/enmasse/address/model/AddressSpaceSchema.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/AddressSpaceSchemaList.java b/api-model/src/main/java/io/enmasse/address/model/AddressSpaceSchemaList.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/AddressSpaceSchemaList.java
rename to api-model/src/main/java/io/enmasse/address/model/AddressSpaceSchemaList.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/AddressSpaceStatus.java b/api-model/src/main/java/io/enmasse/address/model/AddressSpaceStatus.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/AddressSpaceStatus.java
rename to api-model/src/main/java/io/enmasse/address/model/AddressSpaceStatus.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/AddressSpaceType.java b/api-model/src/main/java/io/enmasse/address/model/AddressSpaceType.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/AddressSpaceType.java
rename to api-model/src/main/java/io/enmasse/address/model/AddressSpaceType.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/AddressType.java b/api-model/src/main/java/io/enmasse/address/model/AddressType.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/AddressType.java
rename to api-model/src/main/java/io/enmasse/address/model/AddressType.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/AuthenticationService.java b/api-model/src/main/java/io/enmasse/address/model/AuthenticationService.java
similarity index 88%
rename from address-model-lib/src/main/java/io/enmasse/address/model/AuthenticationService.java
rename to api-model/src/main/java/io/enmasse/address/model/AuthenticationService.java
index 7b7f4e041..6bcf63c05 100644
--- a/address-model-lib/src/main/java/io/enmasse/address/model/AuthenticationService.java
+++ b/api-model/src/main/java/io/enmasse/address/model/AuthenticationService.java
@@ -43,15 +43,6 @@ public class AuthenticationService {
         return Objects.hash(type, details);
     }
 
-    @Override
-    public String toString() {
-        return new StringBuilder()
-                .append("{type=").append(type)
-                .append(",").append("details=").append(details)
-                .append("}")
-                .toString();
-    }
-
     public static class Builder {
         private AuthenticationServiceType type = AuthenticationServiceType.NONE;
         private Map<String, Object> details = new HashMap<>();
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/AuthenticationServiceDetail.java b/api-model/src/main/java/io/enmasse/address/model/AuthenticationServiceDetail.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/AuthenticationServiceDetail.java
rename to api-model/src/main/java/io/enmasse/address/model/AuthenticationServiceDetail.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/AuthenticationServiceResolver.java b/api-model/src/main/java/io/enmasse/address/model/AuthenticationServiceResolver.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/AuthenticationServiceResolver.java
rename to api-model/src/main/java/io/enmasse/address/model/AuthenticationServiceResolver.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/AuthenticationServiceType.java b/api-model/src/main/java/io/enmasse/address/model/AuthenticationServiceType.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/AuthenticationServiceType.java
rename to api-model/src/main/java/io/enmasse/address/model/AuthenticationServiceType.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/CertSpec.java b/api-model/src/main/java/io/enmasse/address/model/CertSpec.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/CertSpec.java
rename to api-model/src/main/java/io/enmasse/address/model/CertSpec.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/EndpointSpec.java b/api-model/src/main/java/io/enmasse/address/model/EndpointSpec.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/EndpointSpec.java
rename to api-model/src/main/java/io/enmasse/address/model/EndpointSpec.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/EndpointStatus.java b/api-model/src/main/java/io/enmasse/address/model/EndpointStatus.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/EndpointStatus.java
rename to api-model/src/main/java/io/enmasse/address/model/EndpointStatus.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/ExposeSpec.java b/api-model/src/main/java/io/enmasse/address/model/ExposeSpec.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/ExposeSpec.java
rename to api-model/src/main/java/io/enmasse/address/model/ExposeSpec.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/InfraConfigDeserializer.java b/api-model/src/main/java/io/enmasse/address/model/InfraConfigDeserializer.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/InfraConfigDeserializer.java
rename to api-model/src/main/java/io/enmasse/address/model/InfraConfigDeserializer.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/KubeUtil.java b/api-model/src/main/java/io/enmasse/address/model/KubeUtil.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/KubeUtil.java
rename to api-model/src/main/java/io/enmasse/address/model/KubeUtil.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/Plan.java b/api-model/src/main/java/io/enmasse/address/model/Plan.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/Plan.java
rename to api-model/src/main/java/io/enmasse/address/model/Plan.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/Schema.java b/api-model/src/main/java/io/enmasse/address/model/Schema.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/Schema.java
rename to api-model/src/main/java/io/enmasse/address/model/Schema.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/Status.java b/api-model/src/main/java/io/enmasse/address/model/Status.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/Status.java
rename to api-model/src/main/java/io/enmasse/address/model/Status.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/UnresolvedAddressException.java b/api-model/src/main/java/io/enmasse/address/model/UnresolvedAddressException.java
similarity index 85%
rename from address-model-lib/src/main/java/io/enmasse/address/model/UnresolvedAddressException.java
rename to api-model/src/main/java/io/enmasse/address/model/UnresolvedAddressException.java
index 81b2c9fc3..eb82c9d13 100644
--- a/address-model-lib/src/main/java/io/enmasse/address/model/UnresolvedAddressException.java
+++ b/api-model/src/main/java/io/enmasse/address/model/UnresolvedAddressException.java
@@ -5,6 +5,9 @@
 package io.enmasse.address.model;
 
 public class UnresolvedAddressException extends RuntimeException {
+
+    private static final long serialVersionUID = 1L;
+
     public UnresolvedAddressException(String message) {
         super(message);
     }
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/UnresolvedAddressSpaceException.java b/api-model/src/main/java/io/enmasse/address/model/UnresolvedAddressSpaceException.java
similarity index 85%
rename from address-model-lib/src/main/java/io/enmasse/address/model/UnresolvedAddressSpaceException.java
rename to api-model/src/main/java/io/enmasse/address/model/UnresolvedAddressSpaceException.java
index 302038d4b..39c699170 100644
--- a/address-model-lib/src/main/java/io/enmasse/address/model/UnresolvedAddressSpaceException.java
+++ b/api-model/src/main/java/io/enmasse/address/model/UnresolvedAddressSpaceException.java
@@ -5,6 +5,9 @@
 package io.enmasse.address.model;
 
 public class UnresolvedAddressSpaceException extends RuntimeException {
+
+    private static final long serialVersionUID = 1L;
+
     public UnresolvedAddressSpaceException(String s) {
         super(s);
     }
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/v1/AddressAndAddressListDeserializer.java b/api-model/src/main/java/io/enmasse/address/model/v1/AddressAndAddressListDeserializer.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/v1/AddressAndAddressListDeserializer.java
rename to api-model/src/main/java/io/enmasse/address/model/v1/AddressAndAddressListDeserializer.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/v1/AddressListV1Deserializer.java b/api-model/src/main/java/io/enmasse/address/model/v1/AddressListV1Deserializer.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/v1/AddressListV1Deserializer.java
rename to api-model/src/main/java/io/enmasse/address/model/v1/AddressListV1Deserializer.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/v1/AddressListV1Serializer.java b/api-model/src/main/java/io/enmasse/address/model/v1/AddressListV1Serializer.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/v1/AddressListV1Serializer.java
rename to api-model/src/main/java/io/enmasse/address/model/v1/AddressListV1Serializer.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/v1/AddressSpaceListV1Deserializer.java b/api-model/src/main/java/io/enmasse/address/model/v1/AddressSpaceListV1Deserializer.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/v1/AddressSpaceListV1Deserializer.java
rename to api-model/src/main/java/io/enmasse/address/model/v1/AddressSpaceListV1Deserializer.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/v1/AddressSpaceListV1Serializer.java b/api-model/src/main/java/io/enmasse/address/model/v1/AddressSpaceListV1Serializer.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/v1/AddressSpaceListV1Serializer.java
rename to api-model/src/main/java/io/enmasse/address/model/v1/AddressSpaceListV1Serializer.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/v1/AddressSpaceSchemaV1Serializer.java b/api-model/src/main/java/io/enmasse/address/model/v1/AddressSpaceSchemaV1Serializer.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/v1/AddressSpaceSchemaV1Serializer.java
rename to api-model/src/main/java/io/enmasse/address/model/v1/AddressSpaceSchemaV1Serializer.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/v1/AddressSpaceV1Deserializer.java b/api-model/src/main/java/io/enmasse/address/model/v1/AddressSpaceV1Deserializer.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/v1/AddressSpaceV1Deserializer.java
rename to api-model/src/main/java/io/enmasse/address/model/v1/AddressSpaceV1Deserializer.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/v1/AddressSpaceV1Serializer.java b/api-model/src/main/java/io/enmasse/address/model/v1/AddressSpaceV1Serializer.java
similarity index 99%
rename from address-model-lib/src/main/java/io/enmasse/address/model/v1/AddressSpaceV1Serializer.java
rename to api-model/src/main/java/io/enmasse/address/model/v1/AddressSpaceV1Serializer.java
index 16bbc0541..6ba86369d 100644
--- a/address-model-lib/src/main/java/io/enmasse/address/model/v1/AddressSpaceV1Serializer.java
+++ b/api-model/src/main/java/io/enmasse/address/model/v1/AddressSpaceV1Serializer.java
@@ -5,7 +5,6 @@
 package io.enmasse.address.model.v1;
 
 import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.JsonSerializer;
 import com.fasterxml.jackson.databind.SerializerProvider;
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/v1/AddressV1Deserializer.java b/api-model/src/main/java/io/enmasse/address/model/v1/AddressV1Deserializer.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/v1/AddressV1Deserializer.java
rename to api-model/src/main/java/io/enmasse/address/model/v1/AddressV1Deserializer.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/v1/AddressV1Serializer.java b/api-model/src/main/java/io/enmasse/address/model/v1/AddressV1Serializer.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/v1/AddressV1Serializer.java
rename to api-model/src/main/java/io/enmasse/address/model/v1/AddressV1Serializer.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/v1/CodecV1.java b/api-model/src/main/java/io/enmasse/address/model/v1/CodecV1.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/v1/CodecV1.java
rename to api-model/src/main/java/io/enmasse/address/model/v1/CodecV1.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/v1/DecodeContext.java b/api-model/src/main/java/io/enmasse/address/model/v1/DecodeContext.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/v1/DecodeContext.java
rename to api-model/src/main/java/io/enmasse/address/model/v1/DecodeContext.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/v1/DeserializeException.java b/api-model/src/main/java/io/enmasse/address/model/v1/DeserializeException.java
similarity index 85%
rename from address-model-lib/src/main/java/io/enmasse/address/model/v1/DeserializeException.java
rename to api-model/src/main/java/io/enmasse/address/model/v1/DeserializeException.java
index bc2cf01ae..42c2ad6a4 100644
--- a/address-model-lib/src/main/java/io/enmasse/address/model/v1/DeserializeException.java
+++ b/api-model/src/main/java/io/enmasse/address/model/v1/DeserializeException.java
@@ -5,6 +5,9 @@
 package io.enmasse.address.model.v1;
 
 public class DeserializeException extends RuntimeException {
+
+    private static final long serialVersionUID = 1L;
+
     public DeserializeException(String s) {
         super(s);
     }
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/v1/Either.java b/api-model/src/main/java/io/enmasse/address/model/v1/Either.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/v1/Either.java
rename to api-model/src/main/java/io/enmasse/address/model/v1/Either.java
diff --git a/address-model-lib/src/main/java/io/enmasse/address/model/v1/Fields.java b/api-model/src/main/java/io/enmasse/address/model/v1/Fields.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/address/model/v1/Fields.java
rename to api-model/src/main/java/io/enmasse/address/model/v1/Fields.java
diff --git a/api-model/src/main/java/io/enmasse/admin/model/v1/AbstractInfraConfig.java b/api-model/src/main/java/io/enmasse/admin/model/v1/AbstractInfraConfig.java
new file mode 100644
index 000000000..6707a95a2
--- /dev/null
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/AbstractInfraConfig.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2018, EnMasse authors.
+ * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
+ */
+
+package io.enmasse.admin.model.v1;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+
+import io.enmasse.common.model.AbstractHasMetadata;
+import io.fabric8.kubernetes.api.model.Doneable;
+import io.sundr.builder.annotations.Buildable;
+import io.sundr.builder.annotations.BuildableReference;
+import io.sundr.builder.annotations.Inline;
+
+@Buildable(
+        editableEnabled = false,
+        generateBuilderPackage = false,
+        builderPackage = "io.fabric8.kubernetes.api.builder",
+        refs= {@BuildableReference(AbstractHasMetadata.class)},
+        inline = @Inline(type = Doneable.class, prefix = "Doneable", value = "done")
+)
+@SuppressWarnings("serial")
+public abstract class AbstractInfraConfig<T> extends AbstractHasMetadata<T> implements InfraConfig {
+
+    private Map<String, Object> additionalProperties = new HashMap<>(0);
+
+    protected AbstractInfraConfig(String kind, String apiVersion) {
+        super(kind, apiVersion);
+    }
+
+    @Override
+    public void setAdditionalProperties(final Map<String, Object> additionalProperties) {
+        this.additionalProperties = additionalProperties;
+    }
+
+    @Override
+    @JsonAnyGetter
+    public Map<String, Object> getAdditionalProperties() {
+        return this.additionalProperties;
+    }
+
+    @Override
+    @JsonAnySetter
+    public void setAdditionalProperty(final String name, final Object value) {
+        this.additionalProperties.put(name, value);
+    }
+
+
+}
diff --git a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/ResourceRequest.java b/api-model/src/main/java/io/enmasse/admin/model/v1/AbstractWithAdditionalProperties.java
similarity index 59%
rename from address-model-lib/src/main/java/io/enmasse/admin/model/v1/ResourceRequest.java
rename to api-model/src/main/java/io/enmasse/admin/model/v1/AbstractWithAdditionalProperties.java
index 4203844f6..7ddf8b52c 100644
--- a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/ResourceRequest.java
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/AbstractWithAdditionalProperties.java
@@ -2,51 +2,44 @@
  * Copyright 2018, EnMasse authors.
  * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
  */
+
 package io.enmasse.admin.model.v1;
 
-import com.fasterxml.jackson.annotation.*;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+
 import io.fabric8.kubernetes.api.model.Doneable;
 import io.sundr.builder.annotations.Buildable;
 import io.sundr.builder.annotations.Inline;
 
-import java.util.HashMap;
-import java.util.Map;
-
 @Buildable(
         editableEnabled = false,
         generateBuilderPackage = false,
         builderPackage = "io.fabric8.kubernetes.api.builder",
         inline = @Inline(type = Doneable.class, prefix = "Doneable", value = "done")
 )
-@JsonPropertyOrder({"name", "credit"})
-@JsonInclude(JsonInclude.Include.NON_NULL)
-public class ResourceRequest {
-    private final String name;
-    private final double credit;
-    private Map<String, Object> additionalProperties = new HashMap<>(0);
-
-    @JsonCreator
-    public ResourceRequest(@JsonProperty("name") String name,
-                           @JsonProperty("credit") double credit) {
-        this.name = name;
-        this.credit = credit;
-    }
+public abstract class AbstractWithAdditionalProperties implements WithAdditionalProperties {
 
-    public String getName() {
-        return name;
-    }
+    private Map<String, Object> additionalProperties = new HashMap<>(0);
 
-    public double getCredit() {
-        return credit;
+    @Override
+    public void setAdditionalProperties(final Map<String, Object> additionalProperties) {
+        this.additionalProperties = additionalProperties;
     }
 
+    @Override
     @JsonAnyGetter
     public Map<String, Object> getAdditionalProperties() {
         return this.additionalProperties;
     }
 
+    @Override
     @JsonAnySetter
-    public void setAdditionalProperty(String name, Object value) {
+    public void setAdditionalProperty(final String name, final Object value) {
         this.additionalProperties.put(name, value);
     }
+
 }
diff --git a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/AddressPlan.java b/api-model/src/main/java/io/enmasse/admin/model/v1/AddressPlan.java
similarity index 54%
rename from address-model-lib/src/main/java/io/enmasse/admin/model/v1/AddressPlan.java
rename to api-model/src/main/java/io/enmasse/admin/model/v1/AddressPlan.java
index 72dda3812..637a38b21 100644
--- a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/AddressPlan.java
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/AddressPlan.java
@@ -2,95 +2,73 @@
  * Copyright 2018, EnMasse authors.
  * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
  */
-package io.enmasse.admin.model.v1;
 
-import com.fasterxml.jackson.annotation.*;
-import com.fasterxml.jackson.databind.JsonDeserializer;
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import io.fabric8.kubernetes.api.model.Doneable;
-import io.fabric8.kubernetes.api.model.HasMetadata;
-import io.fabric8.kubernetes.api.model.ObjectMeta;
-import io.sundr.builder.annotations.Buildable;
-import io.sundr.builder.annotations.Inline;
+package io.enmasse.admin.model.v1;
 
 import java.util.HashMap;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 
-@JsonDeserialize(
-        using = JsonDeserializer.None.class
-)
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+
+import io.enmasse.common.model.AbstractHasMetadata;
+import io.enmasse.common.model.DefaultCustomResource;
+import io.fabric8.kubernetes.api.model.Doneable;
+import io.sundr.builder.annotations.Buildable;
+import io.sundr.builder.annotations.BuildableReference;
+import io.sundr.builder.annotations.Inline;
+
 @Buildable(
         editableEnabled = false,
         generateBuilderPackage = false,
         builderPackage = "io.fabric8.kubernetes.api.builder",
+        refs= {@BuildableReference(AbstractHasMetadata.class)},
         inline = @Inline(type = Doneable.class, prefix = "Doneable", value = "done")
 )
-@JsonPropertyOrder({"apiVersion", "kind", "metadata", "spec"})
-@JsonInclude(JsonInclude.Include.NON_NULL)
-public class AddressPlan implements HasMetadata {
-
-    public static final String ADDRESS_PLAN = "AddressPlan";
-    @JsonProperty("apiVersion")
-    private String apiVersion = "admin.enmasse.io/v1alpha1";
-
-    @JsonProperty("kind")
-    private String kind = ADDRESS_PLAN;
+@DefaultCustomResource
+@SuppressWarnings("serial")
+public class AddressPlan extends AbstractHasMetadata<AddressPlan> {
 
-    private ObjectMeta metadata;
+    public static final String KIND = "AddressPlan";
+    public static final String VERSION = "v1alpha1";
+    public static final String GROUP = "admin.enmasse.io";
+    public static final String API_VERSION = GROUP + "/" + VERSION;
 
-    private final String shortDescription;
-    private final String uuid;
-    private final String addressType;
+    private String shortDescription;
+    private String uuid;
+    private String addressType;
 
-    private final List<ResourceRequest> requiredResources;
+    private List<ResourceRequest> requiredResources = new LinkedList<>();
 
     private Map<String, Object> additionalProperties = new HashMap<>(0);
 
-    @JsonCreator
-    public AddressPlan(@JsonProperty("shortDescription") String shortDescription,
-                       @JsonProperty("uuid") String uuid,
-                       @JsonProperty("addressType") String addressType,
-                       @JsonProperty("requiredResources") List<ResourceRequest> requiredResources) {
-        this.shortDescription = shortDescription;
-        this.uuid = uuid;
-        this.addressType = addressType;
-        this.requiredResources = requiredResources;
+    public AddressPlan() {
+        super(KIND, API_VERSION);
     }
 
+    public void setRequiredResources(List<ResourceRequest> requiredResources) {
+        this.requiredResources = requiredResources;
+    }
+    
     public List<ResourceRequest> getRequiredResources() {
         return requiredResources;
     }
 
-    public ObjectMeta getMetadata() {
-        return metadata;
-    }
-
-    @Override
-    public void setMetadata(ObjectMeta metadata) {
-        this.metadata = metadata;
-    }
-
-    @Override
-    public String getKind() {
-        return kind;
-    }
-
-    @Override
-    public String getApiVersion() {
-        return apiVersion;
-    }
-
-    @Override
-    public void setApiVersion(String s) {
-        this.apiVersion = s;
+    public void setAddressType(String addressType) {
+        this.addressType = addressType;
     }
 
     public String getAddressType() {
         return addressType;
     }
 
+    public void setShortDescription(String shortDescription) {
+        this.shortDescription = shortDescription;
+    }
+
     public String getShortDescription() {
         return shortDescription;
     }
@@ -105,24 +83,28 @@ public class AddressPlan implements HasMetadata {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
         AddressPlan that = (AddressPlan) o;
-        return Objects.equals(metadata, that.metadata) &&
+        return Objects.equals(getMetadata(), that.getMetadata()) &&
                 Objects.equals(uuid, that.uuid);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(metadata, uuid);
+        return Objects.hash(getMetadata(), uuid);
     }
 
     @Override
     public String toString() {
         return "AddressPlan{" +
-                "metadata='" + metadata+ '\'' +
+                "metadata='" + getMetadata() + '\'' +
                 ", uuid='" + uuid + '\'' +
                 ", requiredResources=" + requiredResources +
                 '}';
     }
 
+    public void setUuid(String uuid) {
+        this.uuid = uuid;
+    }
+    
     public String getUuid() {
         return uuid;
     }
@@ -132,6 +114,10 @@ public class AddressPlan implements HasMetadata {
         return this.additionalProperties;
     }
 
+    public void setAdditionalProperties(Map<String, Object> additionalProperties) {
+        this.additionalProperties = additionalProperties;
+    }
+
     @JsonAnySetter
     public void setAdditionalProperty(String name, Object value) {
         this.additionalProperties.put(name, value);
diff --git a/api-model/src/main/java/io/enmasse/admin/model/v1/AddressPlanList.java b/api-model/src/main/java/io/enmasse/admin/model/v1/AddressPlanList.java
new file mode 100644
index 000000000..426c39922
--- /dev/null
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/AddressPlanList.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2018, EnMasse authors.
+ * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
+ */
+package io.enmasse.admin.model.v1;
+
+import io.enmasse.common.model.AbstractList;
+import io.enmasse.common.model.DefaultCustomResource;
+
+@DefaultCustomResource
+@SuppressWarnings("serial")
+public class AddressPlanList extends AbstractList<AddressPlan> {
+
+    public static final String KIND = "AddressPlanList";
+    public static final String VERSION = "v1alpha1";
+    public static final String GROUP = "admin.enmasse.io";
+    public static final String API_VERSION = GROUP + "/" + VERSION;
+
+    public AddressPlanList() {
+        super(KIND, API_VERSION);
+    }
+
+}
diff --git a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/AddressSpacePlan.java b/api-model/src/main/java/io/enmasse/admin/model/v1/AddressSpacePlan.java
similarity index 50%
rename from address-model-lib/src/main/java/io/enmasse/admin/model/v1/AddressSpacePlan.java
rename to api-model/src/main/java/io/enmasse/admin/model/v1/AddressSpacePlan.java
index 84a09019b..879d746ca 100644
--- a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/AddressSpacePlan.java
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/AddressSpacePlan.java
@@ -4,101 +4,86 @@
  */
 package io.enmasse.admin.model.v1;
 
-import com.fasterxml.jackson.annotation.*;
-import com.fasterxml.jackson.databind.JsonDeserializer;
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+
+import io.enmasse.common.model.AbstractHasMetadata;
+import io.enmasse.common.model.DefaultCustomResource;
 import io.fabric8.kubernetes.api.model.Doneable;
-import io.fabric8.kubernetes.api.model.HasMetadata;
-import io.fabric8.kubernetes.api.model.ObjectMeta;
 import io.sundr.builder.annotations.Buildable;
+import io.sundr.builder.annotations.BuildableReference;
 import io.sundr.builder.annotations.Inline;
 
-import java.util.*;
-
-@JsonDeserialize(
-    using = JsonDeserializer.None.class
-)
 @Buildable(
         editableEnabled = false,
         generateBuilderPackage = false,
         builderPackage = "io.fabric8.kubernetes.api.builder",
+        refs= {@BuildableReference(AbstractHasMetadata.class)},
         inline = @Inline(type = Doneable.class, prefix = "Doneable", value = "done")
 )
-@JsonPropertyOrder({"apiVersion", "kind", "metadata", "spec"})
-@JsonInclude(JsonInclude.Include.NON_NULL)
-public class AddressSpacePlan implements HasMetadata {
-    public static final String ADDRESS_SPACE_PLAN = "AddressSpacePlan";
-    private static final long serialVersionUID = 1L;
-
-    @JsonProperty("apiVersion")
-    private String apiVersion = "admin.enmasse.io/v1alpha1";
+@DefaultCustomResource
+@SuppressWarnings("serial")
+public class AddressSpacePlan extends AbstractHasMetadata<AddressSpacePlan> {
 
-    @JsonProperty("kind")
-    private String kind = ADDRESS_SPACE_PLAN;
+    public static final String KIND = "AddressSpacePlan";
+    public static final String VERSION = "v1alpha1";
+    public static final String GROUP = "admin.enmasse.io";
+    public static final String API_VERSION = GROUP + "/" + VERSION;
 
-    private ObjectMeta metadata;
-
-    private final String shortDescription;
-    private final String uuid;
-    private final String addressSpaceType;
-    private final List<ResourceAllowance> resources;
-    private final List<String> addressPlans;
+    private String shortDescription;
+    private String uuid;
+    private String addressSpaceType;
+    private List<ResourceAllowance> resources = new LinkedList<>();
+    private List<String> addressPlans = new LinkedList<>();
 
     private Map<String, Object> additionalProperties = new HashMap<>(0);
 
-    @JsonCreator
-    public AddressSpacePlan(@JsonProperty("shortDescription") String shortDescription,
-                            @JsonProperty("uuid") String uuid,
-                            @JsonProperty("addressSpaceType") String addressSpaceType,
-                            @JsonProperty("resources") List<ResourceAllowance> resources,
-                            @JsonProperty("addressPlans") List<String> addressPlans) {
-        this.shortDescription = shortDescription;
-        this.uuid = uuid;
-        this.addressSpaceType = addressSpaceType;
-        this.resources = resources;
-        this.addressPlans = addressPlans;
+    public AddressSpacePlan() {
+        super(KIND, API_VERSION);
     }
 
+    public void setResources(List<ResourceAllowance> resources) {
+        this.resources = resources;
+    }
+    
     public List<ResourceAllowance> getResources() {
         return resources;
     }
 
+    public void setAddressPlans(List<String> addressPlans) {
+        this.addressPlans = addressPlans;
+    }
+
     public List<String> getAddressPlans() {
         return addressPlans;
     }
 
+    public void setShortDescription(String shortDescription) {
+        this.shortDescription = shortDescription;
+    }
+    
     public String getShortDescription() {
         return shortDescription;
     }
 
-    public ObjectMeta getMetadata() {
-        return metadata;
-    }
-
-    @Override
-    public void setMetadata(ObjectMeta metadata) {
-        this.metadata = metadata;
-    }
-
-    @Override
-    public String getKind() {
-        return kind;
-    }
-
-    @Override
-    public String getApiVersion() {
-        return apiVersion;
-    }
-
-    @Override
-    public void setApiVersion(String apiVersion) {
-        this.apiVersion = apiVersion;
+    public void setAddressSpaceType(String addressSpaceType) {
+        this.addressSpaceType = addressSpaceType;
     }
-
+    
     public String getAddressSpaceType() {
         return addressSpaceType;
     }
 
+    public void setUuid(String uuid) {
+        this.uuid = uuid;
+    }
+    
     public String getUuid() {
         return uuid;
     }
@@ -108,19 +93,19 @@ public class AddressSpacePlan implements HasMetadata {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
         AddressSpacePlan that = (AddressSpacePlan) o;
-        return Objects.equals(metadata, that.metadata) &&
+        return Objects.equals(getMetadata(), that.getMetadata()) &&
                 Objects.equals(uuid, that.uuid);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(metadata, uuid);
+        return Objects.hash(getMetadata(), uuid);
     }
 
     @Override
     public String toString() {
         return "AddressSpacePlan{" +
-                "metadata='" + metadata+ '\'' +
+                "metadata='" + getMetadata()+ '\'' +
                 ", uuid='" + uuid + '\'' +
                 ", resources=" + resources +
                 ", addressPlans=" + addressPlans +
@@ -132,6 +117,10 @@ public class AddressSpacePlan implements HasMetadata {
         return this.additionalProperties;
     }
 
+    public void setAdditionalProperties(Map<String, Object> additionalProperties) {
+        this.additionalProperties = additionalProperties;
+    }
+
     @JsonAnySetter
     public void setAdditionalProperty(String name, Object value) {
         this.additionalProperties.put(name, value);
diff --git a/api-model/src/main/java/io/enmasse/admin/model/v1/AddressSpacePlanList.java b/api-model/src/main/java/io/enmasse/admin/model/v1/AddressSpacePlanList.java
new file mode 100644
index 000000000..f5fe5820d
--- /dev/null
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/AddressSpacePlanList.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2018, EnMasse authors.
+ * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
+ */
+package io.enmasse.admin.model.v1;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+
+import io.enmasse.common.model.AbstractList;
+import io.enmasse.common.model.DefaultCustomResource;
+
+@DefaultCustomResource
+@SuppressWarnings("serial")
+public class AddressSpacePlanList extends AbstractList<AddressSpacePlan> {
+
+    public static final String KIND = "AddressSpacePlanList";
+    public static final String VERSION = "v1alpha1";
+    public static final String GROUP = "admin.enmasse.io";
+    public static final String API_VERSION = GROUP + "/" + VERSION;
+
+    @JsonCreator
+    public AddressSpacePlanList() {
+        super(KIND, API_VERSION);
+    }
+}
diff --git a/api-model/src/main/java/io/enmasse/admin/model/v1/AdminCrd.java b/api-model/src/main/java/io/enmasse/admin/model/v1/AdminCrd.java
new file mode 100644
index 000000000..ce61e27e2
--- /dev/null
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/AdminCrd.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2018, EnMasse authors.
+ * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
+ */
+package io.enmasse.admin.model.v1;
+
+import io.enmasse.common.model.CustomResources;
+import io.fabric8.kubernetes.api.model.apiextensions.CustomResourceDefinition;
+import io.fabric8.kubernetes.internal.KubernetesDeserializer;
+
+public class AdminCrd {
+
+    private static final CustomResourceDefinition ADDRESS_PLAN_CRD;
+    private static final CustomResourceDefinition ADDRESS_SPACE_PLAN_CRD;
+    private static final CustomResourceDefinition BROKERED_INFRA_CONFIG_CRD;
+    private static final CustomResourceDefinition STANDARD_INFRA_CONFIG_CRD;
+
+    static {
+        ADDRESS_PLAN_CRD = CustomResources.createCustomResource(AddressPlan.GROUP, AddressPlan.VERSION, AddressPlan.KIND);
+        ADDRESS_SPACE_PLAN_CRD = CustomResources.createCustomResource(AddressSpacePlan.GROUP, AddressSpacePlan.VERSION, AddressSpacePlan.KIND);
+        BROKERED_INFRA_CONFIG_CRD = CustomResources.createCustomResource(BrokeredInfraConfig.GROUP, BrokeredInfraConfig.VERSION, BrokeredInfraConfig.KIND);
+        STANDARD_INFRA_CONFIG_CRD = CustomResources.createCustomResource(StandardInfraConfig.GROUP, StandardInfraConfig.VERSION, StandardInfraConfig.KIND);
+    }
+
+    public static void registerCustomCrds() {
+
+        KubernetesDeserializer.registerCustomKind(AddressPlan.API_VERSION, AddressPlan.KIND, AddressPlan.class);
+        KubernetesDeserializer.registerCustomKind(AddressPlanList.API_VERSION, AddressPlanList.KIND, AddressPlanList.class);
+
+        KubernetesDeserializer.registerCustomKind(AddressSpacePlan.API_VERSION, AddressSpacePlan.KIND, AddressSpacePlan.class);
+        KubernetesDeserializer.registerCustomKind(AddressSpacePlanList.API_VERSION, AddressSpacePlanList.KIND, AddressSpacePlanList.class);
+
+        KubernetesDeserializer.registerCustomKind(BrokeredInfraConfig.API_VERSION, BrokeredInfraConfig.KIND, BrokeredInfraConfig.class);
+        KubernetesDeserializer.registerCustomKind(BrokeredInfraConfigList.API_VERSION, BrokeredInfraConfigList.KIND, BrokeredInfraConfigList.class);
+
+        KubernetesDeserializer.registerCustomKind(StandardInfraConfig.API_VERSION, StandardInfraConfig.KIND, StandardInfraConfig.class);
+        KubernetesDeserializer.registerCustomKind(StandardInfraConfigList.API_VERSION, StandardInfraConfigList.KIND, StandardInfraConfigList.class);
+
+    }
+
+    public static CustomResourceDefinition addressPlans() {
+        return ADDRESS_PLAN_CRD;
+    }
+
+    public static CustomResourceDefinition addressSpacePlans() {
+        return ADDRESS_SPACE_PLAN_CRD;
+    }
+
+    public static CustomResourceDefinition brokeredInfraConfigs() {
+        return BROKERED_INFRA_CONFIG_CRD;
+    }
+
+    public static CustomResourceDefinition standardInfraConfigs() {
+        return STANDARD_INFRA_CONFIG_CRD;
+    }
+
+}
diff --git a/api-model/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfig.java b/api-model/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfig.java
new file mode 100644
index 000000000..69b7080f0
--- /dev/null
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfig.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2018, EnMasse authors.
+ * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
+ */
+package io.enmasse.admin.model.v1;
+
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+import io.enmasse.common.model.AbstractHasMetadata;
+import io.enmasse.common.model.DefaultCustomResource;
+import io.fabric8.kubernetes.api.model.Doneable;
+import io.sundr.builder.annotations.Buildable;
+import io.sundr.builder.annotations.BuildableReference;
+import io.sundr.builder.annotations.Inline;
+
+@Buildable(
+        editableEnabled = false,
+        generateBuilderPackage = false,
+        builderPackage = "io.fabric8.kubernetes.api.builder",
+        refs= {
+                @BuildableReference(AbstractInfraConfig.class),
+                @BuildableReference(AbstractHasMetadata.class)
+        },
+        inline = @Inline(type = Doneable.class, prefix = "Doneable", value = "done")
+)
+@DefaultCustomResource
+@SuppressWarnings("serial")
+public class BrokeredInfraConfig extends AbstractInfraConfig<BrokeredInfraConfig> {
+
+    public static final String KIND = "BrokeredInfraConfig";
+    public static final String VERSION = "v1alpha1";
+    public static final String GROUP = "admin.enmasse.io";
+    public static final String API_VERSION = GROUP + "/" + VERSION;
+
+    private BrokeredInfraConfigSpec spec;
+
+    public BrokeredInfraConfig() {
+        super(KIND, API_VERSION);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        BrokeredInfraConfig that = (BrokeredInfraConfig) o;
+        return Objects.equals(getMetadata(), that.getMetadata()) &&
+                Objects.equals(spec, that.spec);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(getMetadata(), spec);
+    }
+
+    @Override
+    public String toString() {
+        return "BrokeredInfraConfig{" +
+                "metadata=" + getMetadata() +
+                ", spec=" + spec + "}";
+    }
+
+    public void setSpec(BrokeredInfraConfigSpec spec) {
+        this.spec = spec;
+    }
+
+    public BrokeredInfraConfigSpec getSpec() {
+        return spec;
+    }
+
+    @Override
+    @JsonIgnore
+    public String getVersion() {
+        return spec.getVersion();
+    }
+
+    @Override
+    @JsonIgnore
+    public NetworkPolicy getNetworkPolicy() {
+        return spec.getNetworkPolicy();
+    }
+
+    @Override
+    @JsonIgnore
+    public boolean getUpdatePersistentVolumeClaim() {
+        return spec.getBroker().getUpdatePersistentVolumeClaim() != null ? spec.getBroker().getUpdatePersistentVolumeClaim() : false;
+    }
+
+}
diff --git a/api-model/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigList.java b/api-model/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigList.java
new file mode 100644
index 000000000..3e3d233c5
--- /dev/null
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigList.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2018, EnMasse authors.
+ * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
+ */
+package io.enmasse.admin.model.v1;
+
+import io.enmasse.common.model.AbstractList;
+import io.enmasse.common.model.DefaultCustomResource;
+
+@DefaultCustomResource
+@SuppressWarnings("serial")
+public class BrokeredInfraConfigList extends AbstractList<BrokeredInfraConfig> {
+
+    public static final String KIND = "BrokeredInfraConfigList";
+    public static final String VERSION = "v1alpha1";
+    public static final String GROUP = "admin.enmasse.io";
+    public static final String API_VERSION = GROUP + "/" + VERSION;
+
+    public BrokeredInfraConfigList() {
+        super(KIND, API_VERSION);
+    }
+}
diff --git a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigSpec.java b/api-model/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigSpec.java
similarity index 62%
rename from address-model-lib/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigSpec.java
rename to api-model/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigSpec.java
index 30745f2dc..cb527812d 100644
--- a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigSpec.java
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigSpec.java
@@ -4,41 +4,33 @@
  */
 package io.enmasse.admin.model.v1;
 
-import com.fasterxml.jackson.annotation.*;
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
 import io.fabric8.kubernetes.api.model.Doneable;
 import io.sundr.builder.annotations.Buildable;
+import io.sundr.builder.annotations.BuildableReference;
 import io.sundr.builder.annotations.Inline;
 
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-
 @Buildable(
         editableEnabled = false,
         generateBuilderPackage = false,
         builderPackage = "io.fabric8.kubernetes.api.builder",
+        refs= {
+                @BuildableReference(AbstractWithAdditionalProperties.class)
+        },
         inline = @Inline(type = Doneable.class, prefix = "Doneable", value = "done")
 )
 @JsonPropertyOrder({"version", "admin", "broker"})
 @JsonInclude(JsonInclude.Include.NON_NULL)
-public class BrokeredInfraConfigSpec {
-
-    private final String version;
-    private final NetworkPolicy networkPolicy;
-    private final BrokeredInfraConfigSpecAdmin admin;
-    private final BrokeredInfraConfigSpecBroker broker;
-    private final Map<String, Object> additionalProperties = new HashMap<>(0);
+public class BrokeredInfraConfigSpec extends AbstractWithAdditionalProperties {
 
-    @JsonCreator
-    public BrokeredInfraConfigSpec(@JsonProperty("version") String version,
-                                   @JsonProperty("networkPolicy") NetworkPolicy networkPolicy,
-                                   @JsonProperty("admin") BrokeredInfraConfigSpecAdmin admin,
-                                   @JsonProperty("broker") BrokeredInfraConfigSpecBroker broker) {
-        this.version = version;
-        this.networkPolicy = networkPolicy;
-        this.admin = admin;
-        this.broker = broker;
-    }
+    private String version;
+    private NetworkPolicy networkPolicy;
+    private BrokeredInfraConfigSpecAdmin admin;
+    private BrokeredInfraConfigSpecBroker broker;
 
     @Override
     public boolean equals(Object o) {
@@ -56,26 +48,32 @@ public class BrokeredInfraConfigSpec {
         return Objects.hash(version, networkPolicy, admin, broker);
     }
 
+    public void setAdmin(BrokeredInfraConfigSpecAdmin admin) {
+        this.admin = admin;
+    }
+
     public BrokeredInfraConfigSpecAdmin getAdmin() {
         return admin;
     }
 
+    public void setBroker(BrokeredInfraConfigSpecBroker broker) {
+        this.broker = broker;
+    }
+
     public BrokeredInfraConfigSpecBroker getBroker() {
         return broker;
     }
 
-    public String getVersion() {
-        return version;
+    public void setVersion(String version) {
+        this.version = version;
     }
 
-    @JsonAnyGetter
-    public Map<String, Object> getAdditionalProperties() {
-        return this.additionalProperties;
+    public String getVersion() {
+        return version;
     }
 
-    @JsonAnySetter
-    public void setAdditionalProperty(String name, Object value) {
-        this.additionalProperties.put(name, value);
+    public void setNetworkPolicy(NetworkPolicy networkPolicy) {
+        this.networkPolicy = networkPolicy;
     }
 
     public NetworkPolicy getNetworkPolicy() {
diff --git a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigSpecAdmin.java b/api-model/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigSpecAdmin.java
similarity index 64%
rename from address-model-lib/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigSpecAdmin.java
rename to api-model/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigSpecAdmin.java
index 0b6cc3c6c..5078a9232 100644
--- a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigSpecAdmin.java
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigSpecAdmin.java
@@ -4,15 +4,15 @@
  */
 package io.enmasse.admin.model.v1;
 
-import com.fasterxml.jackson.annotation.*;
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
 import io.fabric8.kubernetes.api.model.Doneable;
 import io.sundr.builder.annotations.Buildable;
 import io.sundr.builder.annotations.Inline;
 
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-
 @Buildable(
         editableEnabled = false,
         generateBuilderPackage = false,
@@ -21,13 +21,14 @@ import java.util.Objects;
 )
 @JsonPropertyOrder({"resources"})
 @JsonInclude(JsonInclude.Include.NON_NULL)
-public class BrokeredInfraConfigSpecAdmin {
-    private final BrokeredInfraConfigSpecAdminResources resources;
-    private Map<String, Object> additionalProperties = new HashMap<>(0);
+public class BrokeredInfraConfigSpecAdmin extends AbstractWithAdditionalProperties {
+    private BrokeredInfraConfigSpecAdminResources resources;
 
-    @JsonCreator
-    public BrokeredInfraConfigSpecAdmin(@JsonProperty("resources") BrokeredInfraConfigSpecAdminResources resources) {
-        this.resources = resources;
+    public BrokeredInfraConfigSpecAdmin() {
+    }
+
+    public BrokeredInfraConfigSpecAdmin(final BrokeredInfraConfigSpecAdminResources resources) {
+        setResources(resources);
     }
 
     @Override
@@ -43,17 +44,12 @@ public class BrokeredInfraConfigSpecAdmin {
         return Objects.hash(resources);
     }
 
-    public BrokeredInfraConfigSpecAdminResources getResources() {
-        return resources;
+    public void setResources(BrokeredInfraConfigSpecAdminResources resources) {
+        this.resources = resources;
     }
 
-    @JsonAnyGetter
-    public Map<String, Object> getAdditionalProperties() {
-        return this.additionalProperties;
+    public BrokeredInfraConfigSpecAdminResources getResources() {
+        return resources;
     }
 
-    @JsonAnySetter
-    public void setAdditionalProperty(String name, Object value) {
-        this.additionalProperties.put(name, value);
-    }
 }
diff --git a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigSpecAdminResources.java b/api-model/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigSpecAdminResources.java
similarity index 66%
rename from address-model-lib/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigSpecAdminResources.java
rename to api-model/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigSpecAdminResources.java
index b9fae0a1c..00485004f 100644
--- a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigSpecAdminResources.java
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigSpecAdminResources.java
@@ -4,15 +4,15 @@
  */
 package io.enmasse.admin.model.v1;
 
-import com.fasterxml.jackson.annotation.*;
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
 import io.fabric8.kubernetes.api.model.Doneable;
 import io.sundr.builder.annotations.Buildable;
 import io.sundr.builder.annotations.Inline;
 
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-
 @Buildable(
         editableEnabled = false,
         generateBuilderPackage = false,
@@ -21,13 +21,15 @@ import java.util.Objects;
 )
 @JsonPropertyOrder({"memory"})
 @JsonInclude(JsonInclude.Include.NON_NULL)
-public class BrokeredInfraConfigSpecAdminResources {
-    private final String memory;
+public class BrokeredInfraConfigSpecAdminResources extends AbstractWithAdditionalProperties {
+    private String memory;
 
-    public BrokeredInfraConfigSpecAdminResources(@JsonProperty("memory") String memory) {
-        this.memory = memory;
+    public BrokeredInfraConfigSpecAdminResources() {
+    }
+
+    public BrokeredInfraConfigSpecAdminResources(final String memory) {
+        setMemory(memory);
     }
-    private Map<String, Object> additionalProperties = new HashMap<>(0);
 
     @Override
     public boolean equals(Object o) {
@@ -42,17 +44,12 @@ public class BrokeredInfraConfigSpecAdminResources {
         return Objects.hash(memory);
     }
 
-    public String getMemory() {
-        return memory;
+    public void setMemory(String memory) {
+        this.memory = memory;
     }
 
-    @JsonAnyGetter
-    public Map<String, Object> getAdditionalProperties() {
-        return this.additionalProperties;
+    public String getMemory() {
+        return memory;
     }
 
-    @JsonAnySetter
-    public void setAdditionalProperty(String name, Object value) {
-        this.additionalProperties.put(name, value);
-    }
 }
diff --git a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigSpecBroker.java b/api-model/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigSpecBroker.java
similarity index 62%
rename from address-model-lib/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigSpecBroker.java
rename to api-model/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigSpecBroker.java
index 0a3b7a587..0b4b64800 100644
--- a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigSpecBroker.java
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigSpecBroker.java
@@ -4,15 +4,15 @@
  */
 package io.enmasse.admin.model.v1;
 
-import com.fasterxml.jackson.annotation.*;
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
 import io.fabric8.kubernetes.api.model.Doneable;
 import io.sundr.builder.annotations.Buildable;
 import io.sundr.builder.annotations.Inline;
 
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-
 @Buildable(
         editableEnabled = false,
         generateBuilderPackage = false,
@@ -21,22 +21,16 @@ import java.util.Objects;
 )
 @JsonPropertyOrder({"resources", "addressFullPolicy", "storageClassName", "updatePersistentVolumeClaim"})
 @JsonInclude(JsonInclude.Include.NON_NULL)
-public class BrokeredInfraConfigSpecBroker {
-    private final BrokeredInfraConfigSpecBrokerResources resources;
-    private final String addressFullPolicy;
-    private final String storageClassName;
-    private final Boolean updatePersistentVolumeClaim;
-    private Map<String, Object> additionalProperties = new HashMap<>(0);
-
-    @JsonCreator
-    public BrokeredInfraConfigSpecBroker(@JsonProperty("resources") BrokeredInfraConfigSpecBrokerResources resources,
-                                         @JsonProperty("addressFullPolicy") String addressFullPolicy,
-                                         @JsonProperty("storageClassName") String storageClassName,
-                                         @JsonProperty("updatePersistentVolumeClaim") Boolean updatePersistentVolumeClaim) {
-        this.resources = resources;
-        this.addressFullPolicy = addressFullPolicy;
-        this.storageClassName = storageClassName;
-        this.updatePersistentVolumeClaim = updatePersistentVolumeClaim;
+public class BrokeredInfraConfigSpecBroker extends AbstractWithAdditionalProperties {
+    private BrokeredInfraConfigSpecBrokerResources resources;
+    private String addressFullPolicy;
+    private String storageClassName;
+    private Boolean updatePersistentVolumeClaim;
+
+    public BrokeredInfraConfigSpecBroker() {
+    }
+
+    public BrokeredInfraConfigSpecBroker(final BrokeredInfraConfigSpecBrokerResources resources) {
     }
 
     @Override
@@ -55,29 +49,45 @@ public class BrokeredInfraConfigSpecBroker {
         return Objects.hash(resources, addressFullPolicy, storageClassName, updatePersistentVolumeClaim);
     }
 
+    public void setResources(BrokeredInfraConfigSpecBrokerResources resources) {
+        this.resources = resources;
+    }
+
     public BrokeredInfraConfigSpecBrokerResources getResources() {
         return resources;
     }
 
+    public void setAddressFullPolicy(String addressFullPolicy) {
+        this.addressFullPolicy = addressFullPolicy;
+    }
+
     public String getAddressFullPolicy() {
         return addressFullPolicy;
     }
 
+    public void setStorageClassName(String storageClassName) {
+        this.storageClassName = storageClassName;
+    }
+
     public String getStorageClassName() {
         return storageClassName;
     }
 
-    public Boolean getUpdatePersistentVolumeClaim() {
-        return updatePersistentVolumeClaim;
+    public void setUpdatePersistentVolumeClaim(Boolean updatePersistentVolumeClaim) {
+        this.updatePersistentVolumeClaim = updatePersistentVolumeClaim;
     }
 
-    @JsonAnyGetter
-    public Map<String, Object> getAdditionalProperties() {
-        return this.additionalProperties;
+    /*
+     * NOTE: This is required due to a bug in the builder generator. For a boolean object
+     * type it requires an "is" type of the getter. Luckily we can hide this behind the "default"
+     * visibility. Also the "is" variant must appear before the "get" variant.
+     */
+    Boolean isUpdatePersistentVolumeClaim() {
+        return updatePersistentVolumeClaim;
     }
 
-    @JsonAnySetter
-    public void setAdditionalProperty(String name, Object value) {
-        this.additionalProperties.put(name, value);
+    public Boolean getUpdatePersistentVolumeClaim() {
+        return updatePersistentVolumeClaim;
     }
+
 }
diff --git a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigSpecBrokerResources.java b/api-model/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigSpecBrokerResources.java
similarity index 64%
rename from address-model-lib/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigSpecBrokerResources.java
rename to api-model/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigSpecBrokerResources.java
index 7e66a8cd3..fc004511f 100644
--- a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigSpecBrokerResources.java
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigSpecBrokerResources.java
@@ -4,15 +4,15 @@
  */
 package io.enmasse.admin.model.v1;
 
-import com.fasterxml.jackson.annotation.*;
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
 import io.fabric8.kubernetes.api.model.Doneable;
 import io.sundr.builder.annotations.Buildable;
 import io.sundr.builder.annotations.Inline;
 
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-
 @Buildable(
         editableEnabled = false,
         generateBuilderPackage = false,
@@ -21,15 +21,16 @@ import java.util.Objects;
 )
 @JsonPropertyOrder({"memory", "storage"})
 @JsonInclude(JsonInclude.Include.NON_NULL)
-public class BrokeredInfraConfigSpecBrokerResources {
-    private final String memory;
-    private final String storage;
-    private Map<String, Object> additionalProperties = new HashMap<>(0);
+public class BrokeredInfraConfigSpecBrokerResources extends AbstractWithAdditionalProperties {
+    private String memory;
+    private String storage;
 
-    public BrokeredInfraConfigSpecBrokerResources(@JsonProperty("memory") String memory,
-                                                    @JsonProperty("storage") String storage) {
-        this.memory = memory;
-        this.storage = storage;
+    public BrokeredInfraConfigSpecBrokerResources() {
+    }
+
+    public BrokeredInfraConfigSpecBrokerResources(final String memory, final String storage) {
+        setMemory(memory);
+        setStorage(storage);
     }
 
     @Override
@@ -46,21 +47,20 @@ public class BrokeredInfraConfigSpecBrokerResources {
         return Objects.hash(memory, storage);
     }
 
+    public void setMemory(String memory) {
+        this.memory = memory;
+    }
+
     public String getMemory() {
         return memory;
     }
 
-    public String getStorage() {
-        return storage;
+    public void setStorage(String storage) {
+        this.storage = storage;
     }
 
-    @JsonAnyGetter
-    public Map<String, Object> getAdditionalProperties() {
-        return this.additionalProperties;
+    public String getStorage() {
+        return storage;
     }
 
-    @JsonAnySetter
-    public void setAdditionalProperty(String name, Object value) {
-        this.additionalProperties.put(name, value);
-    }
 }
diff --git a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/InfraConfig.java b/api-model/src/main/java/io/enmasse/admin/model/v1/InfraConfig.java
similarity index 81%
rename from address-model-lib/src/main/java/io/enmasse/admin/model/v1/InfraConfig.java
rename to api-model/src/main/java/io/enmasse/admin/model/v1/InfraConfig.java
index 2c783ade0..a7207eaea 100644
--- a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/InfraConfig.java
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/InfraConfig.java
@@ -6,7 +6,7 @@ package io.enmasse.admin.model.v1;
 
 import io.fabric8.kubernetes.api.model.HasMetadata;
 
-public interface InfraConfig extends HasMetadata {
+public interface InfraConfig extends HasMetadata, WithAdditionalProperties {
     String getVersion();
     NetworkPolicy getNetworkPolicy();
     boolean getUpdatePersistentVolumeClaim();
diff --git a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/NetworkPolicy.java b/api-model/src/main/java/io/enmasse/admin/model/v1/NetworkPolicy.java
similarity index 90%
rename from address-model-lib/src/main/java/io/enmasse/admin/model/v1/NetworkPolicy.java
rename to api-model/src/main/java/io/enmasse/admin/model/v1/NetworkPolicy.java
index 47ccb58ed..ccdb1b1e9 100644
--- a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/NetworkPolicy.java
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/NetworkPolicy.java
@@ -4,21 +4,25 @@
  */
 package io.enmasse.admin.model.v1;
 
-import com.fasterxml.jackson.annotation.*;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
 import com.fasterxml.jackson.databind.JsonDeserializer;
 import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+
 import io.fabric8.kubernetes.api.model.Doneable;
 import io.fabric8.kubernetes.api.model.networking.NetworkPolicyEgressRule;
 import io.fabric8.kubernetes.api.model.networking.NetworkPolicyIngressRule;
-import io.fabric8.kubernetes.api.model.networking.NetworkPolicyPeer;
 import io.sundr.builder.annotations.Buildable;
 import io.sundr.builder.annotations.Inline;
 
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-
 @JsonDeserialize(
         using = JsonDeserializer.None.class
 )
diff --git a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/ResourceAllowance.java b/api-model/src/main/java/io/enmasse/admin/model/v1/ResourceAllowance.java
similarity index 60%
rename from address-model-lib/src/main/java/io/enmasse/admin/model/v1/ResourceAllowance.java
rename to api-model/src/main/java/io/enmasse/admin/model/v1/ResourceAllowance.java
index 0f049deee..d46d4e71f 100644
--- a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/ResourceAllowance.java
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/ResourceAllowance.java
@@ -4,16 +4,15 @@
  */
 package io.enmasse.admin.model.v1;
 
-import com.fasterxml.jackson.annotation.*;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
 import com.fasterxml.jackson.databind.JsonDeserializer;
 import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+
 import io.fabric8.kubernetes.api.model.Doneable;
 import io.sundr.builder.annotations.Buildable;
 import io.sundr.builder.annotations.Inline;
 
-import java.util.HashMap;
-import java.util.Map;
-
 @JsonDeserialize(
         using = JsonDeserializer.None.class
 )
@@ -25,34 +24,33 @@ import java.util.Map;
 )
 @JsonPropertyOrder({"name", "max"})
 @JsonInclude(JsonInclude.Include.NON_NULL)
-public class ResourceAllowance {
-    private final String name;
-    private final double max;
+public class ResourceAllowance extends AbstractWithAdditionalProperties {
 
-    @JsonCreator
-    public ResourceAllowance(@JsonProperty("name") String name,
-                             @JsonProperty("max") double max) {
-        this.name = name;
-        this.max = max;
+    private String name;
+    private double max;
+
+    public ResourceAllowance() {
     }
 
-    private Map<String, Object> additionalProperties = new HashMap<>(0);
+    public ResourceAllowance(final String name, final double max) {
+        setName(name);
+        setMax(max);
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
 
     public String getName() {
         return name;
     }
 
-    public double getMax() {
-        return max;
+    public void setMax(double max) {
+        this.max = max;
     }
 
-    @JsonAnyGetter
-    public Map<String, Object> getAdditionalProperties() {
-        return this.additionalProperties;
+    public double getMax() {
+        return max;
     }
 
-    @JsonAnySetter
-    public void setAdditionalProperty(String name, Object value) {
-        this.additionalProperties.put(name, value);
-    }
 }
diff --git a/api-model/src/main/java/io/enmasse/admin/model/v1/ResourceRequest.java b/api-model/src/main/java/io/enmasse/admin/model/v1/ResourceRequest.java
new file mode 100644
index 000000000..8e5e5fd46
--- /dev/null
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/ResourceRequest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2018, EnMasse authors.
+ * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
+ */
+package io.enmasse.admin.model.v1;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
+import io.fabric8.kubernetes.api.model.Doneable;
+import io.sundr.builder.annotations.Buildable;
+import io.sundr.builder.annotations.Inline;
+
+@Buildable(
+        editableEnabled = false,
+        generateBuilderPackage = false,
+        builderPackage = "io.fabric8.kubernetes.api.builder",
+        inline = @Inline(type = Doneable.class, prefix = "Doneable", value = "done")
+)
+@JsonPropertyOrder({"name", "credit"})
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class ResourceRequest extends AbstractWithAdditionalProperties {
+
+    private String name;
+    private double credit;
+
+    public ResourceRequest() {
+    }
+
+    public ResourceRequest(final String name, final double credit) {
+        setName(name);
+        setCredit(credit);
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setCredit(double credit) {
+        this.credit = credit;
+    }
+
+    public double getCredit() {
+        return credit;
+    }
+
+}
diff --git a/api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfig.java b/api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfig.java
new file mode 100644
index 000000000..6d0abcefa
--- /dev/null
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfig.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2018, EnMasse authors.
+ * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
+ */
+package io.enmasse.admin.model.v1;
+
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+import io.enmasse.common.model.AbstractHasMetadata;
+import io.enmasse.common.model.DefaultCustomResource;
+import io.fabric8.kubernetes.api.model.Doneable;
+import io.sundr.builder.annotations.Buildable;
+import io.sundr.builder.annotations.BuildableReference;
+import io.sundr.builder.annotations.Inline;
+
+@Buildable(
+        editableEnabled = false,
+        generateBuilderPackage = false,
+        builderPackage = "io.fabric8.kubernetes.api.builder",
+        refs= {
+                @BuildableReference(AbstractInfraConfig.class),
+                @BuildableReference(AbstractHasMetadata.class)
+        },
+        inline = @Inline(type = Doneable.class, prefix = "Doneable", value = "done")
+)
+@DefaultCustomResource
+@SuppressWarnings("serial")
+public class StandardInfraConfig extends AbstractInfraConfig<StandardInfraConfig> {
+
+    public static final String KIND = "StandardInfraConfig";
+    public static final String VERSION = "v1alpha1";
+    public static final String GROUP = "admin.enmasse.io";
+    public static final String API_VERSION = GROUP + "/" + VERSION;
+
+    private StandardInfraConfigSpec spec;
+
+    public StandardInfraConfig() {
+        super(KIND, API_VERSION);
+    }
+
+    public void setSpec(StandardInfraConfigSpec spec) {
+        this.spec = spec;
+    }
+
+    public StandardInfraConfigSpec getSpec() {
+        return spec;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        StandardInfraConfig that = (StandardInfraConfig) o;
+        return Objects.equals(getMetadata(), that.getMetadata()) &&
+                Objects.equals(spec, that.spec);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(getMetadata(), spec);
+    }
+
+    @Override
+    public String toString() {
+        return "StandardInfraConfig{" +
+                "metadata=" + getMetadata() +
+                ", spec=" + spec + "}";
+    }
+
+    @Override
+    @JsonIgnore
+    public String getVersion() {
+        return spec.getVersion();
+    }
+
+    @Override
+    @JsonIgnore
+    public NetworkPolicy getNetworkPolicy() {
+        return spec.getNetworkPolicy();
+    }
+
+    @Override
+    @JsonIgnore
+    public boolean getUpdatePersistentVolumeClaim() {
+        return spec.getBroker().getUpdatePersistentVolumeClaim() != null ? spec.getBroker().getUpdatePersistentVolumeClaim() : false;
+    }
+}
diff --git a/api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigList.java b/api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigList.java
new file mode 100644
index 000000000..3d8bdd321
--- /dev/null
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigList.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2018, EnMasse authors.
+ * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
+ */
+package io.enmasse.admin.model.v1;
+
+import io.enmasse.common.model.AbstractList;
+import io.enmasse.common.model.DefaultCustomResource;
+
+@DefaultCustomResource
+@SuppressWarnings("serial")
+public class StandardInfraConfigList extends AbstractList<StandardInfraConfig>{
+
+    public static final String KIND = "StandardInfraConfigList";
+    public static final String VERSION = "v1alpha1";
+    public static final String GROUP = "admin.enmasse.io";
+    public static final String API_VERSION = GROUP + "/" + VERSION;
+
+    public StandardInfraConfigList() {
+        super(KIND, API_VERSION);
+    }
+
+}
diff --git a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpec.java b/api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpec.java
similarity index 61%
rename from address-model-lib/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpec.java
rename to api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpec.java
index 645c9c775..a0284ada9 100644
--- a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpec.java
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpec.java
@@ -4,15 +4,15 @@
  */
 package io.enmasse.admin.model.v1;
 
-import com.fasterxml.jackson.annotation.*;
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
 import io.fabric8.kubernetes.api.model.Doneable;
 import io.sundr.builder.annotations.Buildable;
 import io.sundr.builder.annotations.Inline;
 
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-
 @Buildable(
         editableEnabled = false,
         generateBuilderPackage = false,
@@ -21,41 +21,42 @@ import java.util.Objects;
 )
 @JsonPropertyOrder({"version", "admin", "broker", "router"})
 @JsonInclude(JsonInclude.Include.NON_NULL)
-public class StandardInfraConfigSpec {
-
-    private final String version;
-    private final NetworkPolicy networkPolicy;
-    private final StandardInfraConfigSpecAdmin admin;
-    private final StandardInfraConfigSpecBroker broker;
-    private final StandardInfraConfigSpecRouter router;
-
-    @JsonCreator
-    public StandardInfraConfigSpec(@JsonProperty("version") String version,
-                                   @JsonProperty("networkPolicy") NetworkPolicy networkPolicy,
-                                   @JsonProperty("admin") StandardInfraConfigSpecAdmin admin,
-                                   @JsonProperty("broker") StandardInfraConfigSpecBroker broker,
-                                   @JsonProperty("router") StandardInfraConfigSpecRouter router) {
+public class StandardInfraConfigSpec extends AbstractWithAdditionalProperties {
+
+    private String version;
+    private NetworkPolicy networkPolicy;
+    private StandardInfraConfigSpecAdmin admin;
+    private StandardInfraConfigSpecBroker broker;
+    private StandardInfraConfigSpecRouter router;
+
+    public void setVersion(String version) {
         this.version = version;
-        this.networkPolicy = networkPolicy;
-        this.admin = admin;
-        this.broker = broker;
-        this.router = router;
     }
 
-    private Map<String, Object> additionalProperties = new HashMap<>(0);
-
     public String getVersion() {
         return version;
     }
 
+    public void setAdmin(StandardInfraConfigSpecAdmin admin) {
+        this.admin = admin;
+    }
+
     public StandardInfraConfigSpecAdmin getAdmin() {
         return admin;
     }
 
+    public void setBroker(StandardInfraConfigSpecBroker broker) {
+        this.broker = broker;
+    }
+
     public StandardInfraConfigSpecBroker getBroker() {
         return broker;
     }
 
+    public void setRouter(StandardInfraConfigSpecRouter router) {
+        this.router = router;
+    }
+
     public StandardInfraConfigSpecRouter getRouter() {
         return router;
     }
@@ -77,14 +78,8 @@ public class StandardInfraConfigSpec {
         return Objects.hash(version, networkPolicy, admin, broker, router);
     }
 
-    @JsonAnyGetter
-    public Map<String, Object> getAdditionalProperties() {
-        return this.additionalProperties;
-    }
-
-    @JsonAnySetter
-    public void setAdditionalProperty(String name, Object value) {
-        this.additionalProperties.put(name, value);
+    public void setNetworkPolicy(NetworkPolicy networkPolicy) {
+        this.networkPolicy = networkPolicy;
     }
 
     public NetworkPolicy getNetworkPolicy() {
diff --git a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecAdmin.java b/api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecAdmin.java
similarity index 64%
rename from address-model-lib/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecAdmin.java
rename to api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecAdmin.java
index f97f50e28..f5c5e6782 100644
--- a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecAdmin.java
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecAdmin.java
@@ -4,15 +4,15 @@
  */
 package io.enmasse.admin.model.v1;
 
-import com.fasterxml.jackson.annotation.*;
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
 import io.fabric8.kubernetes.api.model.Doneable;
 import io.sundr.builder.annotations.Buildable;
 import io.sundr.builder.annotations.Inline;
 
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-
 @Buildable(
         editableEnabled = false,
         generateBuilderPackage = false,
@@ -21,12 +21,18 @@ import java.util.Objects;
 )
 @JsonPropertyOrder({"resources"})
 @JsonInclude(JsonInclude.Include.NON_NULL)
-public class StandardInfraConfigSpecAdmin {
-    private final StandardInfraConfigSpecAdminResources resources;
-    private Map<String, Object> additionalProperties = new HashMap<>(0);
+public class StandardInfraConfigSpecAdmin extends AbstractWithAdditionalProperties {
+
+    private StandardInfraConfigSpecAdminResources resources;
 
-    @JsonCreator
-    public StandardInfraConfigSpecAdmin(@JsonProperty("resources") StandardInfraConfigSpecAdminResources resources) {
+    public StandardInfraConfigSpecAdmin() {
+    }
+
+    public StandardInfraConfigSpecAdmin(StandardInfraConfigSpecAdminResources resources) {
+        setResources(resources);
+    }
+
+    public void setResources(StandardInfraConfigSpecAdminResources resources) {
         this.resources = resources;
     }
 
@@ -47,13 +53,4 @@ public class StandardInfraConfigSpecAdmin {
         return Objects.hash(resources);
     }
 
-    @JsonAnyGetter
-    public Map<String, Object> getAdditionalProperties() {
-        return this.additionalProperties;
-    }
-
-    @JsonAnySetter
-    public void setAdditionalProperty(String name, Object value) {
-        this.additionalProperties.put(name, value);
-    }
 }
diff --git a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecAdminResources.java b/api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecAdminResources.java
similarity index 66%
rename from address-model-lib/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecAdminResources.java
rename to api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecAdminResources.java
index 9bf8575f7..35702bac5 100644
--- a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecAdminResources.java
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecAdminResources.java
@@ -4,15 +4,15 @@
  */
 package io.enmasse.admin.model.v1;
 
-import com.fasterxml.jackson.annotation.*;
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
 import io.fabric8.kubernetes.api.model.Doneable;
 import io.sundr.builder.annotations.Buildable;
 import io.sundr.builder.annotations.Inline;
 
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-
 @Buildable(
         editableEnabled = false,
         generateBuilderPackage = false,
@@ -21,11 +21,17 @@ import java.util.Objects;
 )
 @JsonPropertyOrder({"memory"})
 @JsonInclude(JsonInclude.Include.NON_NULL)
-public class StandardInfraConfigSpecAdminResources {
-    private final String memory;
-    private Map<String, Object> additionalProperties = new HashMap<>(0);
+public class StandardInfraConfigSpecAdminResources extends AbstractWithAdditionalProperties {
+    private String memory;
+
+    public StandardInfraConfigSpecAdminResources() {
+    }
+
+    public StandardInfraConfigSpecAdminResources(final String memory) {
+        setMemory(memory);
+    }
 
-    public StandardInfraConfigSpecAdminResources(@JsonProperty("memory") String memory) {
+    public void setMemory(String memory) {
         this.memory = memory;
     }
 
@@ -46,13 +52,4 @@ public class StandardInfraConfigSpecAdminResources {
         return Objects.hash(memory);
     }
 
-    @JsonAnyGetter
-    public Map<String, Object> getAdditionalProperties() {
-        return this.additionalProperties;
-    }
-
-    @JsonAnySetter
-    public void setAdditionalProperty(String name, Object value) {
-        this.additionalProperties.put(name, value);
-    }
 }
diff --git a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecBroker.java b/api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecBroker.java
similarity index 61%
rename from address-model-lib/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecBroker.java
rename to api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecBroker.java
index 72d4b00c5..38fb7aa0b 100644
--- a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecBroker.java
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecBroker.java
@@ -4,15 +4,15 @@
  */
 package io.enmasse.admin.model.v1;
 
-import com.fasterxml.jackson.annotation.*;
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
 import io.fabric8.kubernetes.api.model.Doneable;
 import io.sundr.builder.annotations.Buildable;
 import io.sundr.builder.annotations.Inline;
 
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-
 @Buildable(
         editableEnabled = false,
         generateBuilderPackage = false,
@@ -21,36 +21,56 @@ import java.util.Objects;
 )
 @JsonPropertyOrder({"resources", "addressFullPolicy", "storageClassName", "updatePersistentVolumeClaim"})
 @JsonInclude(JsonInclude.Include.NON_NULL)
-public class StandardInfraConfigSpecBroker {
-    private final StandardInfraConfigSpecBrokerResources resources;
-    private final String addressFullPolicy;
-    private final String storageClassName;
-    private final Boolean updatePersistentVolumeClaim;
-    private Map<String, Object> additionalProperties = new HashMap<>(0);
-
-    @JsonCreator
-    public StandardInfraConfigSpecBroker(@JsonProperty("resources") StandardInfraConfigSpecBrokerResources resources,
-                                         @JsonProperty("addressFullPolicy") String addressFullPolicy,
-                                         @JsonProperty("storageClassName") String storageClassName,
-                                         @JsonProperty("updatePersistentVolumeClaim") Boolean updatePersistentVolumeClaim) {
+public class StandardInfraConfigSpecBroker extends AbstractWithAdditionalProperties {
+    private StandardInfraConfigSpecBrokerResources resources;
+    private String addressFullPolicy;
+    private String storageClassName;
+    private Boolean updatePersistentVolumeClaim;
+
+    public StandardInfraConfigSpecBroker() {
+    }
+
+    public StandardInfraConfigSpecBroker(final StandardInfraConfigSpecBrokerResources resources) {
+        setResources(resources);
+    }
+
+    public void setResources(StandardInfraConfigSpecBrokerResources resources) {
         this.resources = resources;
-        this.addressFullPolicy = addressFullPolicy;
-        this.storageClassName = storageClassName;
-        this.updatePersistentVolumeClaim = updatePersistentVolumeClaim;
     }
 
     public StandardInfraConfigSpecBrokerResources getResources() {
         return resources;
     }
 
+    public void setAddressFullPolicy(String addressFullPolicy) {
+        this.addressFullPolicy = addressFullPolicy;
+    }
+
     public String getAddressFullPolicy() {
         return addressFullPolicy;
     }
 
+    public void setStorageClassName(String storageClassName) {
+        this.storageClassName = storageClassName;
+    }
+
     public String getStorageClassName() {
         return storageClassName;
     }
 
+    public void setUpdatePersistentVolumeClaim(Boolean updatePersistentVolumeClaim) {
+        this.updatePersistentVolumeClaim = updatePersistentVolumeClaim;
+    }
+
+    /*
+     * NOTE: This is required due to a bug in the builder generator. For a boolean object
+     * type it requires an "is" type of the getter. Luckily we can hide this behind the "default"
+     * visibility. Also the "is" variant must appear before the "get" variant.
+     */
+    Boolean isUpdatePersistentVolumeClaim() {
+        return updatePersistentVolumeClaim;
+    }
+
     public Boolean getUpdatePersistentVolumeClaim() {
         return updatePersistentVolumeClaim;
     }
@@ -71,13 +91,4 @@ public class StandardInfraConfigSpecBroker {
         return Objects.hash(resources, addressFullPolicy, storageClassName, updatePersistentVolumeClaim);
     }
 
-    @JsonAnyGetter
-    public Map<String, Object> getAdditionalProperties() {
-        return this.additionalProperties;
-    }
-
-    @JsonAnySetter
-    public void setAdditionalProperty(String name, Object value) {
-        this.additionalProperties.put(name, value);
-    }
 }
diff --git a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecBrokerResources.java b/api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecBrokerResources.java
similarity index 64%
rename from address-model-lib/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecBrokerResources.java
rename to api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecBrokerResources.java
index 03f538ec5..0a781a173 100644
--- a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecBrokerResources.java
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecBrokerResources.java
@@ -4,15 +4,15 @@
  */
 package io.enmasse.admin.model.v1;
 
-import com.fasterxml.jackson.annotation.*;
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
 import io.fabric8.kubernetes.api.model.Doneable;
 import io.sundr.builder.annotations.Buildable;
 import io.sundr.builder.annotations.Inline;
 
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-
 @Buildable(
         editableEnabled = false,
         generateBuilderPackage = false,
@@ -21,22 +21,30 @@ import java.util.Objects;
 )
 @JsonPropertyOrder({"memory", "storage"})
 @JsonInclude(JsonInclude.Include.NON_NULL)
-public class StandardInfraConfigSpecBrokerResources {
-    private final String memory;
-    private final String storage;
-    private Map<String, Object> additionalProperties = new HashMap<>(0);
+public class StandardInfraConfigSpecBrokerResources extends AbstractWithAdditionalProperties {
+    private String memory;
+    private String storage;
+
+    public StandardInfraConfigSpecBrokerResources() {
+    }
+
+    public StandardInfraConfigSpecBrokerResources(final String memory, final String storage ) {
+        setMemory(memory);
+        setStorage(storage);
+    }
 
-    @JsonCreator
-    public StandardInfraConfigSpecBrokerResources(@JsonProperty("memory") String memory,
-                                                  @JsonProperty("storage") String storage) {
+    public void setMemory(String memory) {
         this.memory = memory;
-        this.storage = storage;
     }
 
     public String getMemory() {
         return memory;
     }
 
+    public void setStorage(String storage) {
+        this.storage = storage;
+    }
+
     public String getStorage() {
         return storage;
     }
@@ -55,13 +63,4 @@ public class StandardInfraConfigSpecBrokerResources {
         return Objects.hash(memory, storage);
     }
 
-    @JsonAnyGetter
-    public Map<String, Object> getAdditionalProperties() {
-        return this.additionalProperties;
-    }
-
-    @JsonAnySetter
-    public void setAdditionalProperty(String name, Object value) {
-        this.additionalProperties.put(name, value);
-    }
 }
diff --git a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecRouter.java b/api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecRouter.java
similarity index 62%
rename from address-model-lib/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecRouter.java
rename to api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecRouter.java
index f04fc9a37..8685342ef 100644
--- a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecRouter.java
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecRouter.java
@@ -4,15 +4,15 @@
  */
 package io.enmasse.admin.model.v1;
 
-import com.fasterxml.jackson.annotation.*;
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
 import io.fabric8.kubernetes.api.model.Doneable;
 import io.sundr.builder.annotations.Buildable;
 import io.sundr.builder.annotations.Inline;
 
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-
 @Buildable(
         editableEnabled = false,
         generateBuilderPackage = false,
@@ -21,25 +21,32 @@ import java.util.Objects;
 )
 @JsonPropertyOrder({"resources", "linkCapacity"})
 @JsonInclude(JsonInclude.Include.NON_NULL)
-public class StandardInfraConfigSpecRouter {
-    private final StandardInfraConfigSpecRouterResources resources;
-    private final int minReplicas;
-    private final int linkCapacity;
-    private Map<String, Object> additionalProperties = new HashMap<>(0);
+public class StandardInfraConfigSpecRouter extends AbstractWithAdditionalProperties {
+    private StandardInfraConfigSpecRouterResources resources;
+    private int minReplicas;
+    private int linkCapacity;
+
+    public StandardInfraConfigSpecRouter() {
+    }
+
+    public StandardInfraConfigSpecRouter(final StandardInfraConfigSpecRouterResources resources, final int minReplicas, final int linkCapacity) {
+        setResources(resources);
+        setMinReplicas(minReplicas);
+        setLinkCapacity(linkCapacity);
+    }
 
-    @JsonCreator
-    public StandardInfraConfigSpecRouter(@JsonProperty("resources") StandardInfraConfigSpecRouterResources resources,
-                                         @JsonProperty("minReplicas") int minReplicas,
-                                         @JsonProperty("linkCapacity") int linkCapacity) {
+    public void setResources(StandardInfraConfigSpecRouterResources resources) {
         this.resources = resources;
-        this.minReplicas = minReplicas;
-        this.linkCapacity = linkCapacity;
     }
 
     public StandardInfraConfigSpecRouterResources getResources() {
         return resources;
     }
 
+    public void setLinkCapacity(int linkCapacity) {
+        this.linkCapacity = linkCapacity;
+    }
+
     public int getLinkCapacity() {
         return linkCapacity;
     }
@@ -58,14 +65,8 @@ public class StandardInfraConfigSpecRouter {
         return Objects.hash(resources, linkCapacity);
     }
 
-    @JsonAnyGetter
-    public Map<String, Object> getAdditionalProperties() {
-        return this.additionalProperties;
-    }
-
-    @JsonAnySetter
-    public void setAdditionalProperty(String name, Object value) {
-        this.additionalProperties.put(name, value);
+    public void setMinReplicas(int minReplicas) {
+        this.minReplicas = minReplicas;
     }
 
     public int getMinReplicas() {
diff --git a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecRouterResources.java b/api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecRouterResources.java
similarity index 65%
rename from address-model-lib/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecRouterResources.java
rename to api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecRouterResources.java
index b07b6949d..4fa608517 100644
--- a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecRouterResources.java
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigSpecRouterResources.java
@@ -4,15 +4,15 @@
  */
 package io.enmasse.admin.model.v1;
 
-import com.fasterxml.jackson.annotation.*;
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
 import io.fabric8.kubernetes.api.model.Doneable;
 import io.sundr.builder.annotations.Buildable;
 import io.sundr.builder.annotations.Inline;
 
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-
 @Buildable(
         editableEnabled = false,
         generateBuilderPackage = false,
@@ -21,12 +21,17 @@ import java.util.Objects;
 )
 @JsonPropertyOrder({"memory"})
 @JsonInclude(JsonInclude.Include.NON_NULL)
-public class StandardInfraConfigSpecRouterResources {
-    private final String memory;
-    private Map<String, Object> additionalProperties = new HashMap<>(0);
+public class StandardInfraConfigSpecRouterResources extends AbstractWithAdditionalProperties {
+    private String memory;
+
+    public StandardInfraConfigSpecRouterResources() {
+    }
+
+    public StandardInfraConfigSpecRouterResources(final String memory) {
+        setMemory(memory);
+    }
 
-    @JsonCreator
-    public StandardInfraConfigSpecRouterResources(@JsonProperty("memory") String memory) {
+    public void setMemory(String memory) {
         this.memory = memory;
     }
 
@@ -47,13 +52,4 @@ public class StandardInfraConfigSpecRouterResources {
         return Objects.hash(memory);
     }
 
-    @JsonAnyGetter
-    public Map<String, Object> getAdditionalProperties() {
-        return this.additionalProperties;
-    }
-
-    @JsonAnySetter
-    public void setAdditionalProperty(String name, Object value) {
-        this.additionalProperties.put(name, value);
-    }
 }
diff --git a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/ValidationFailedException.java b/api-model/src/main/java/io/enmasse/admin/model/v1/ValidationFailedException.java
similarity index 93%
rename from address-model-lib/src/main/java/io/enmasse/admin/model/v1/ValidationFailedException.java
rename to api-model/src/main/java/io/enmasse/admin/model/v1/ValidationFailedException.java
index 17425bb66..c0f84e774 100644
--- a/address-model-lib/src/main/java/io/enmasse/admin/model/v1/ValidationFailedException.java
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/ValidationFailedException.java
@@ -4,7 +4,9 @@
  */
 package io.enmasse.admin.model.v1;
 
+@SuppressWarnings("serial")
 public class ValidationFailedException extends RuntimeException {
+
     public ValidationFailedException(String message) {
         super(message);
     }
diff --git a/api-model/src/main/java/io/enmasse/admin/model/v1/WithAdditionalProperties.java b/api-model/src/main/java/io/enmasse/admin/model/v1/WithAdditionalProperties.java
new file mode 100644
index 000000000..795e92245
--- /dev/null
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/WithAdditionalProperties.java
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2018, EnMasse authors.
+ * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
+ */
+
+package io.enmasse.admin.model.v1;
+
+import java.util.Map;
+
+public interface WithAdditionalProperties {
+
+    Map<String, Object> getAdditionalProperties();
+    void setAdditionalProperties(Map<String, Object> additionalProperties);
+    void setAdditionalProperty(String name, Object value);
+
+}
\ No newline at end of file
diff --git a/api-model/src/main/java/io/enmasse/common/model/AbstractHasMetadata.java b/api-model/src/main/java/io/enmasse/common/model/AbstractHasMetadata.java
new file mode 100644
index 000000000..75ee62aee
--- /dev/null
+++ b/api-model/src/main/java/io/enmasse/common/model/AbstractHasMetadata.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2018, EnMasse authors.
+ * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
+ */
+
+package io.enmasse.common.model;
+
+import io.fabric8.kubernetes.api.model.Doneable;
+import io.fabric8.kubernetes.api.model.HasMetadata;
+import io.fabric8.kubernetes.api.model.ObjectMeta;
+
+import io.sundr.builder.annotations.Buildable;
+import io.sundr.builder.annotations.Inline;
+
+@Buildable(
+                editableEnabled = false,
+                generateBuilderPackage = false,
+                builderPackage = "io.fabric8.kubernetes.api.builder",
+                inline = @Inline(
+                                type = Doneable.class,
+                                prefix = "Doneable",
+                                value = "done"))
+@SuppressWarnings("serial")
+public abstract class AbstractHasMetadata<T> extends AbstractResource<T> implements HasMetadata {
+
+    private ObjectMeta metadata;
+
+    protected AbstractHasMetadata(final String kind, String apiVersion) {
+        super(kind, apiVersion);
+    }
+
+    @Override
+    public ObjectMeta getMetadata() {
+        return this.metadata;
+    }
+
+    @Override
+    public void setMetadata(final ObjectMeta metadata) {
+        this.metadata = metadata;
+    }
+
+}
diff --git a/api-model/src/main/java/io/enmasse/common/model/AbstractList.java b/api-model/src/main/java/io/enmasse/common/model/AbstractList.java
new file mode 100644
index 000000000..6391363b5
--- /dev/null
+++ b/api-model/src/main/java/io/enmasse/common/model/AbstractList.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2018, EnMasse authors.
+ * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
+ */
+
+package io.enmasse.common.model;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import io.fabric8.kubernetes.api.model.HasMetadata;
+import io.fabric8.kubernetes.api.model.KubernetesResource;
+import io.fabric8.kubernetes.api.model.KubernetesResourceList;
+import io.fabric8.kubernetes.api.model.ListMeta;
+
+@SuppressWarnings("serial")
+public abstract class AbstractList<T extends HasMetadata> extends AbstractResource<T>
+                implements KubernetesResource<T>, KubernetesResourceList<T> {
+
+    private ListMeta metadata;
+
+    private List<T> items = new ArrayList<>();
+
+    protected AbstractList(final String kind, final String apiVersion) {
+        super(kind, apiVersion);
+    }
+
+    public void setItems(final Collection<? extends T> items) {
+        this.items = new ArrayList<>(items);
+    }
+
+    public List<T> getItems() {
+        return this.items;
+    }
+
+    public void setMetadata(final ListMeta metadata) {
+        this.metadata = metadata;
+    }
+
+    @Override
+    public ListMeta getMetadata() {
+        return this.metadata;
+    }
+
+    @Override
+    public String toString() {
+        return "{metadata=" + this.metadata + "," +
+                        "items=" + this.items + "}";
+    }
+}
diff --git a/api-model/src/main/java/io/enmasse/common/model/AbstractResource.java b/api-model/src/main/java/io/enmasse/common/model/AbstractResource.java
new file mode 100644
index 000000000..7716eb355
--- /dev/null
+++ b/api-model/src/main/java/io/enmasse/common/model/AbstractResource.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2018, EnMasse authors.
+ * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
+ */
+
+package io.enmasse.common.model;
+
+import io.fabric8.kubernetes.api.model.Doneable;
+import io.sundr.builder.annotations.Buildable;
+import io.sundr.builder.annotations.Inline;
+
+@Buildable(
+                editableEnabled = false,
+                generateBuilderPackage = false,
+                builderPackage = "io.fabric8.kubernetes.api.builder",
+                inline = @Inline(
+                                type = Doneable.class,
+                                prefix = "Doneable",
+                                value = "done"))
+public abstract class AbstractResource<T> {
+
+    private final String kind;
+
+    private String apiVersion;
+
+    protected AbstractResource(final String kind, final String apiVersion) {
+        this.kind = kind;
+        this.apiVersion = apiVersion;
+    }
+
+    public String getKind() {
+        return this.kind;
+    }
+
+    public String getApiVersion() {
+        return this.apiVersion;
+    }
+
+    public void setApiVersion(final String apiVersion) {
+        this.apiVersion = apiVersion;
+    }
+
+}
diff --git a/api-model/src/main/java/io/enmasse/common/model/CustomResources.java b/api-model/src/main/java/io/enmasse/common/model/CustomResources.java
new file mode 100644
index 000000000..d51cae2a6
--- /dev/null
+++ b/api-model/src/main/java/io/enmasse/common/model/CustomResources.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2018, EnMasse authors.
+ * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
+ */
+package io.enmasse.common.model;
+
+import io.fabric8.kubernetes.api.model.apiextensions.CustomResourceDefinition;
+import io.fabric8.kubernetes.api.model.apiextensions.CustomResourceDefinitionBuilder;
+
+public final class CustomResources {
+
+    private CustomResources() {}
+
+    public static CustomResourceDefinition createCustomResource(final String group, final String version, final String kind) {
+        String singular = kind.toLowerCase();
+        String listKind = kind + "List";
+        String plural = singular + "s";
+        return new CustomResourceDefinitionBuilder()
+                        .editOrNewMetadata()
+                        .withName(plural + "." + group)
+                        .addToLabels("app", "enmasse")
+                        .endMetadata()
+                        .editOrNewSpec()
+                        .withGroup(group)
+                        .withVersion(version)
+                        .withScope("Namespaced")
+                        .editOrNewNames()
+                        .withKind(kind)
+                        .withListKind(listKind)
+                        .withPlural(plural)
+                        .withSingular(singular)
+                        .endNames()
+                        .endSpec()
+                        .build();
+    }
+
+}
diff --git a/api-model/src/main/java/io/enmasse/common/model/DefaultCustomResource.java b/api-model/src/main/java/io/enmasse/common/model/DefaultCustomResource.java
new file mode 100644
index 000000000..1a1c0ae7d
--- /dev/null
+++ b/api-model/src/main/java/io/enmasse/common/model/DefaultCustomResource.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2018, EnMasse authors.
+ * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
+ */
+
+package io.enmasse.common.model;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+
+/**
+ * A default set of Jackson annotations for custom resources.
+ */
+@JacksonAnnotationsInside
+@JsonDeserialize(using = com.fasterxml.jackson.databind.JsonDeserializer.None.class)
+@JsonPropertyOrder({"apiVersion", "kind", "metadata"})
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@Retention(RUNTIME)
+@Target(TYPE)
+public @interface DefaultCustomResource {
+
+}
diff --git a/address-model-lib/src/main/java/io/enmasse/config/AnnotationKeys.java b/api-model/src/main/java/io/enmasse/config/AnnotationKeys.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/config/AnnotationKeys.java
rename to api-model/src/main/java/io/enmasse/config/AnnotationKeys.java
diff --git a/address-model-lib/src/main/java/io/enmasse/config/LabelKeys.java b/api-model/src/main/java/io/enmasse/config/LabelKeys.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/config/LabelKeys.java
rename to api-model/src/main/java/io/enmasse/config/LabelKeys.java
diff --git a/address-model-lib/src/main/java/io/enmasse/k8s/model/v1beta1/PartialObjectMetadata.java b/api-model/src/main/java/io/enmasse/k8s/model/v1beta1/PartialObjectMetadata.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/k8s/model/v1beta1/PartialObjectMetadata.java
rename to api-model/src/main/java/io/enmasse/k8s/model/v1beta1/PartialObjectMetadata.java
diff --git a/address-model-lib/src/main/java/io/enmasse/k8s/model/v1beta1/Table.java b/api-model/src/main/java/io/enmasse/k8s/model/v1beta1/Table.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/k8s/model/v1beta1/Table.java
rename to api-model/src/main/java/io/enmasse/k8s/model/v1beta1/Table.java
diff --git a/address-model-lib/src/main/java/io/enmasse/k8s/model/v1beta1/TableColumnDefinition.java b/api-model/src/main/java/io/enmasse/k8s/model/v1beta1/TableColumnDefinition.java
similarity index 100%
rename from address-model-lib/src/main/java/io/enmasse/k8s/model/v1beta1/TableColumnDefinition.java
rename to api-model/src/main/java/io/enmasse/k8s/model/v1beta1/TableColumnDefinition.java
diff --git a/address-model-lib/src/main/java/io/enmasse/k8s/model/v1beta1/TableRow.java b/api-model/src/main/java/io/enmasse/k8s/model/v1beta1/TableRow.java
similarity index 97%
rename from address-model-lib/src/main/java/io/enmasse/k8s/model/v1beta1/TableRow.java
rename to api-model/src/main/java/io/enmasse/k8s/model/v1beta1/TableRow.java
index cbeeffd41..4aec41512 100644
--- a/address-model-lib/src/main/java/io/enmasse/k8s/model/v1beta1/TableRow.java
+++ b/api-model/src/main/java/io/enmasse/k8s/model/v1beta1/TableRow.java
@@ -8,7 +8,6 @@ import com.fasterxml.jackson.annotation.*;
 import com.fasterxml.jackson.databind.JsonDeserializer;
 import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
 import io.fabric8.kubernetes.api.model.Doneable;
-import io.fabric8.kubernetes.api.model.HasMetadata;
 import io.sundr.builder.annotations.Buildable;
 import io.sundr.builder.annotations.Inline;
 
diff --git a/api-model/src/main/java/io/enmasse/model/CustomResourceDefinitions.java b/api-model/src/main/java/io/enmasse/model/CustomResourceDefinitions.java
new file mode 100644
index 000000000..33463da37
--- /dev/null
+++ b/api-model/src/main/java/io/enmasse/model/CustomResourceDefinitions.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2018, EnMasse authors.
+ * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
+ */
+
+package io.enmasse.model;
+
+import io.enmasse.admin.model.v1.AdminCrd;
+import io.enmasse.user.model.v1.UserCrd;
+
+public final class CustomResourceDefinitions {
+
+    private CustomResourceDefinitions() {}
+
+    /**
+     * Register all custom resource definitions used by EnMasse.
+     */
+    public static void registerAll() {
+        AdminCrd.registerCustomCrds();
+        UserCrd.registerCustomCrds();
+    }
+}
diff --git a/user-api/src/main/java/io/enmasse/user/api/UserApi.java b/api-model/src/main/java/io/enmasse/user/api/UserApi.java
similarity index 100%
rename from user-api/src/main/java/io/enmasse/user/api/UserApi.java
rename to api-model/src/main/java/io/enmasse/user/api/UserApi.java
diff --git a/user-api/src/main/java/io/enmasse/user/model/v1/Operation.java b/api-model/src/main/java/io/enmasse/user/model/v1/Operation.java
similarity index 100%
rename from user-api/src/main/java/io/enmasse/user/model/v1/Operation.java
rename to api-model/src/main/java/io/enmasse/user/model/v1/Operation.java
diff --git a/api-model/src/main/java/io/enmasse/user/model/v1/User.java b/api-model/src/main/java/io/enmasse/user/model/v1/User.java
new file mode 100644
index 000000000..9087bcba6
--- /dev/null
+++ b/api-model/src/main/java/io/enmasse/user/model/v1/User.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2017-2018, EnMasse authors.
+ * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
+ */
+package io.enmasse.user.model.v1;
+
+import java.util.Objects;
+import java.util.regex.Pattern;
+
+import io.enmasse.common.model.AbstractHasMetadata;
+import io.enmasse.common.model.DefaultCustomResource;
+import io.fabric8.kubernetes.api.model.Doneable;
+import io.sundr.builder.annotations.Buildable;
+import io.sundr.builder.annotations.BuildableReference;
+import io.sundr.builder.annotations.Inline;
+
+@Buildable(
+        editableEnabled = false,
+        generateBuilderPackage = false,
+        builderPackage = "io.fabric8.kubernetes.api.builder",
+        refs= {@BuildableReference(AbstractHasMetadata.class)},
+        inline = @Inline(
+                type = Doneable.class,
+                prefix = "Doneable",
+                value = "done"
+                )
+        )
+@DefaultCustomResource
+@SuppressWarnings("serial")
+public class User extends AbstractHasMetadata<User> {
+
+    private static final Pattern NAME_PATTERN = Pattern.compile("^[a-z]+([a-z0-9\\-]*[a-z0-9]+|[a-z0-9]*)\\.[a-z0-9]+([a-z0-9@.\\-]*[a-z0-9]+|[a-z0-9]*)$");
+
+    public static final String KIND = "User";
+    public static final String VERSION = "v1alpha1";
+    public static final String GROUP = "user.enmasse.io";
+    public static final String API_VERSION = GROUP +"/" + VERSION;
+
+    public User() {
+        super(KIND,API_VERSION);
+    }
+
+    private UserSpec spec;
+
+    public void setSpec(final UserSpec spec) {
+        this.spec = spec;
+    }
+
+    public UserSpec getSpec() {
+        return spec;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        User user = (User) o;
+        return Objects.equals(getApiVersion(), user.getApiVersion()) &&
+                Objects.equals(getKind(), user.getKind()) &&
+                Objects.equals(getMetadata(), user.getMetadata());
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(getApiVersion(), getKind(), getMetadata(), spec);
+    }
+
+    public void validate() {
+        try {
+
+            validateMetadata();
+
+            Objects.requireNonNull(spec, "'spec' must be set");
+            spec.validate();
+
+        } catch (Exception e) {
+            throw new UserValidationFailedException(e);
+        }
+    }
+
+    private void validateMetadata() {
+        Objects.requireNonNull(getMetadata(), "'metadata' must be set");
+
+        final String name = getMetadata().getName();
+        final String namespace = getMetadata().getNamespace();
+
+        Objects.requireNonNull(name, "'name' must be set");
+        if (!NAME_PATTERN.matcher(name).matches()) {
+            throw new UserValidationFailedException("Invalid resource name '" + name + "', must match " + NAME_PATTERN);
+        }
+        Objects.requireNonNull(namespace, "'namespace' must be set");
+
+    }
+}
diff --git a/user-api/src/main/java/io/enmasse/user/model/v1/UserAuthentication.java b/api-model/src/main/java/io/enmasse/user/model/v1/UserAuthentication.java
similarity index 65%
rename from user-api/src/main/java/io/enmasse/user/model/v1/UserAuthentication.java
rename to api-model/src/main/java/io/enmasse/user/model/v1/UserAuthentication.java
index f11145803..c892a4c66 100644
--- a/user-api/src/main/java/io/enmasse/user/model/v1/UserAuthentication.java
+++ b/api-model/src/main/java/io/enmasse/user/model/v1/UserAuthentication.java
@@ -4,13 +4,25 @@
  */
 package io.enmasse.user.model.v1;
 
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
 import java.util.Objects;
 
-import static io.enmasse.user.model.v1.UserAuthenticationType.federated;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
 
+import io.fabric8.kubernetes.api.model.Doneable;
+import io.sundr.builder.annotations.Buildable;
+import io.sundr.builder.annotations.Inline;
+
+@Buildable(
+        editableEnabled = false,
+        generateBuilderPackage = false,
+        builderPackage = "io.fabric8.kubernetes.api.builder",
+        inline = @Inline(
+                type = Doneable.class,
+                prefix = "Doneable",
+                value = "done"
+                )
+        )
 @JsonInclude(JsonInclude.Include.NON_NULL)
 public class UserAuthentication {
     private final UserAuthenticationType type;
@@ -70,42 +82,4 @@ public class UserAuthentication {
                 break;
         }
     }
-
-    public static class Builder {
-        private UserAuthenticationType type;
-        private String password;
-        private String provider;
-        private String federatedUserid;
-        private String federatedUsername;
-
-        public Builder setType(UserAuthenticationType type) {
-            this.type = type;
-            return this;
-        }
-
-        public Builder setPassword(String password) {
-            this.password = password;
-            return this;
-        }
-
-        public Builder setProvider(String provider) {
-            this.provider = provider;
-            return this;
-        }
-
-        public Builder setFederatedUserid(String federatedUserid) {
-            this.federatedUserid = federatedUserid;
-            return this;
-        }
-
-        public Builder setFederatedUsername(String federatedUsername) {
-            this.federatedUsername = federatedUsername;
-            return this;
-        }
-
-        public UserAuthentication build() {
-            Objects.requireNonNull(type);
-            return new UserAuthentication(type, password, provider, federatedUserid, federatedUsername);
-        }
-    }
 }
diff --git a/user-api/src/main/java/io/enmasse/user/model/v1/UserAuthenticationType.java b/api-model/src/main/java/io/enmasse/user/model/v1/UserAuthenticationType.java
similarity index 100%
rename from user-api/src/main/java/io/enmasse/user/model/v1/UserAuthenticationType.java
rename to api-model/src/main/java/io/enmasse/user/model/v1/UserAuthenticationType.java
diff --git a/user-api/src/main/java/io/enmasse/user/model/v1/UserAuthorization.java b/api-model/src/main/java/io/enmasse/user/model/v1/UserAuthorization.java
similarity index 69%
rename from user-api/src/main/java/io/enmasse/user/model/v1/UserAuthorization.java
rename to api-model/src/main/java/io/enmasse/user/model/v1/UserAuthorization.java
index c5ea5fbb6..95b6b0fcd 100644
--- a/user-api/src/main/java/io/enmasse/user/model/v1/UserAuthorization.java
+++ b/api-model/src/main/java/io/enmasse/user/model/v1/UserAuthorization.java
@@ -4,15 +4,27 @@
  */
 package io.enmasse.user.model.v1;
 
+import java.util.List;
+import java.util.Objects;
+
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonProperty;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Objects;
-
+import io.fabric8.kubernetes.api.model.Doneable;
+import io.sundr.builder.annotations.Buildable;
+import io.sundr.builder.annotations.Inline;
+
+@Buildable(
+        editableEnabled = false,
+        generateBuilderPackage = false,
+        builderPackage = "io.fabric8.kubernetes.api.builder",
+        inline = @Inline(
+                type = Doneable.class,
+                prefix = "Doneable",
+                value = "done"
+                )
+        )
 @JsonInclude(JsonInclude.Include.NON_NULL)
 public class UserAuthorization {
     private final List<String> addresses;
@@ -39,23 +51,4 @@ public class UserAuthorization {
             Objects.requireNonNull(addresses, "'addresses' field must be set for operations '" + operations + "'");
         }
     }
-
-    public static class Builder {
-        private List<String> addresses;
-        private List<Operation> operations;
-
-        public Builder setAddresses(Collection<String> addresses) {
-            this.addresses = new ArrayList<>(addresses);
-            return this;
-        }
-
-        public Builder setOperations(List<Operation> operations) {
-            this.operations = operations;
-            return this;
-        }
-
-        public UserAuthorization build() {
-            return new UserAuthorization(addresses, operations);
-        }
-    }
 }
diff --git a/api-model/src/main/java/io/enmasse/user/model/v1/UserCrd.java b/api-model/src/main/java/io/enmasse/user/model/v1/UserCrd.java
new file mode 100644
index 000000000..43ebde255
--- /dev/null
+++ b/api-model/src/main/java/io/enmasse/user/model/v1/UserCrd.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2018, EnMasse authors.
+ * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
+ */
+package io.enmasse.user.model.v1;
+
+import io.enmasse.common.model.CustomResources;
+import io.fabric8.kubernetes.api.model.apiextensions.CustomResourceDefinition;
+import io.fabric8.kubernetes.internal.KubernetesDeserializer;
+
+public class UserCrd {
+
+    private static final CustomResourceDefinition MESSAGING_USER_CRD;
+
+    static {
+        MESSAGING_USER_CRD = CustomResources.createCustomResource(User.GROUP, User.VERSION, User.KIND);
+    }
+
+    public static void registerCustomCrds() {
+        KubernetesDeserializer.registerCustomKind(User.API_VERSION, User.KIND, User.class);
+        KubernetesDeserializer.registerCustomKind(UserList.API_VERSION, UserList.KIND, UserList.class);
+    }
+
+    public static CustomResourceDefinition messagingUser() {
+        return MESSAGING_USER_CRD;
+    }
+
+}
diff --git a/api-model/src/main/java/io/enmasse/user/model/v1/UserList.java b/api-model/src/main/java/io/enmasse/user/model/v1/UserList.java
new file mode 100644
index 000000000..afaf9df81
--- /dev/null
+++ b/api-model/src/main/java/io/enmasse/user/model/v1/UserList.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2017-2018, EnMasse authors.
+ * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
+ */
+package io.enmasse.user.model.v1;
+
+import io.enmasse.common.model.AbstractList;
+import io.enmasse.common.model.DefaultCustomResource;
+
+@DefaultCustomResource
+@SuppressWarnings("serial")
+public class UserList extends AbstractList<User> {
+
+    public static final String KIND = "MessagingUserList";
+    public static final String VERSION = "v1alpha1";
+    public static final String GROUP = "user.enmasse.io";
+    public static final String API_VERSION = GROUP + "/" + VERSION;
+
+    public UserList() {
+        super(KIND, API_VERSION);
+    }
+}
diff --git a/user-api/src/main/java/io/enmasse/user/model/v1/UserSpec.java b/api-model/src/main/java/io/enmasse/user/model/v1/UserSpec.java
similarity index 60%
rename from user-api/src/main/java/io/enmasse/user/model/v1/UserSpec.java
rename to api-model/src/main/java/io/enmasse/user/model/v1/UserSpec.java
index cee44e9b5..4cb607a9e 100644
--- a/user-api/src/main/java/io/enmasse/user/model/v1/UserSpec.java
+++ b/api-model/src/main/java/io/enmasse/user/model/v1/UserSpec.java
@@ -8,16 +8,32 @@ import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonProperty;
 
+import io.fabric8.kubernetes.api.model.Doneable;
+import io.sundr.builder.annotations.Buildable;
+import io.sundr.builder.annotations.Inline;
+
 import java.util.List;
 import java.util.Objects;
 import java.util.regex.Pattern;
 
+@Buildable(
+        editableEnabled = false,
+        generateBuilderPackage = false,
+        builderPackage = "io.fabric8.kubernetes.api.builder",
+        inline = @Inline(
+                type = Doneable.class,
+                prefix = "Doneable",
+                value = "done"
+                )
+        )
 @JsonInclude(JsonInclude.Include.NON_NULL)
 public class UserSpec {
+    private final static Pattern USERNAME_PATTERN = Pattern.compile("^[a-z0-9]+([a-z0-9_@.\\-]*[a-z0-9]+|[a-z0-9]*)$");
+
     private final String username;
     private final UserAuthentication authentication;
     private final List<UserAuthorization> authorization;
-    private final Pattern usernamePattern = Pattern.compile("^[a-z0-9]+([a-z0-9_@.\\-]*[a-z0-9]+|[a-z0-9]*)$");
+    
 
     @JsonCreator
     public UserSpec(@JsonProperty("username") String username,
@@ -42,8 +58,8 @@ public class UserSpec {
 
     public void validate() {
         Objects.requireNonNull(username, "'username' must be set");
-        if (!usernamePattern.matcher(username).matches()) {
-            throw new UserValidationFailedException("Invalid username '" + username + "', must match " + usernamePattern.toString());
+        if (!USERNAME_PATTERN.matcher(username).matches()) {
+            throw new UserValidationFailedException("Invalid username '" + username + "', must match " + USERNAME_PATTERN.toString());
         }
 
         if (authentication != null) {
@@ -56,32 +72,4 @@ public class UserSpec {
             }
         }
     }
-
-    public static class Builder {
-        private String username;
-        private UserAuthentication authentication;
-        private List<UserAuthorization> authorization;
-
-
-        public Builder setUsername(String username) {
-            this.username = username;
-            return this;
-        }
-
-        public Builder setAuthentication(UserAuthentication authentication) {
-            this.authentication = authentication;
-            return this;
-        }
-
-        public Builder setAuthorization(List<UserAuthorization> authorization) {
-            this.authorization = authorization;
-            return this;
-        }
-
-        public UserSpec build() {
-            Objects.requireNonNull(username);
-            Objects.requireNonNull(authentication);
-            return new UserSpec(username, authentication, authorization);
-        }
-    }
 }
diff --git a/user-api/src/main/java/io/enmasse/user/model/v1/UserValidationFailedException.java b/api-model/src/main/java/io/enmasse/user/model/v1/UserValidationFailedException.java
similarity index 93%
rename from user-api/src/main/java/io/enmasse/user/model/v1/UserValidationFailedException.java
rename to api-model/src/main/java/io/enmasse/user/model/v1/UserValidationFailedException.java
index a71063e58..d5373597e 100644
--- a/user-api/src/main/java/io/enmasse/user/model/v1/UserValidationFailedException.java
+++ b/api-model/src/main/java/io/enmasse/user/model/v1/UserValidationFailedException.java
@@ -4,7 +4,9 @@
  */
 package io.enmasse.user.model.v1;
 
+@SuppressWarnings("serial")
 public class UserValidationFailedException extends RuntimeException {
+
     public UserValidationFailedException(String message) {
         super(message);
     }
@@ -12,4 +14,5 @@ public class UserValidationFailedException extends RuntimeException {
     public UserValidationFailedException(Exception e) {
         super(e);
     }
+
 }
diff --git a/api-server/pom.xml b/api-server/pom.xml
index 40ca28c32..2f856899d 100644
--- a/api-server/pom.xml
+++ b/api-server/pom.xml
@@ -9,11 +9,6 @@
   <modelVersion>4.0.0</modelVersion>
   <artifactId>api-server</artifactId>
   <dependencies>
-    <dependency>
-      <groupId>io.enmasse</groupId>
-      <artifactId>address-model-lib</artifactId>
-      <scope>compile</scope>
-    </dependency>
     <dependency>
       <groupId>io.enmasse</groupId>
       <artifactId>metrics-api</artifactId>
@@ -21,8 +16,7 @@
     </dependency>
     <dependency>
       <groupId>io.enmasse</groupId>
-      <artifactId>user-api</artifactId>
-      <scope>compile</scope>
+      <artifactId>api-model</artifactId>
     </dependency>
     <dependency>
       <groupId>io.enmasse</groupId>
diff --git a/api-server/src/main/java/io/enmasse/api/v1/http/HttpUserService.java b/api-server/src/main/java/io/enmasse/api/v1/http/HttpUserService.java
index dad1d9ee0..5c7e8edb0 100644
--- a/api-server/src/main/java/io/enmasse/api/v1/http/HttpUserService.java
+++ b/api-server/src/main/java/io/enmasse/api/v1/http/HttpUserService.java
@@ -4,6 +4,38 @@
  */
 package io.enmasse.api.v1.http;
 
+import java.time.Clock;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.Callable;
+import java.util.stream.Collectors;
+
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.BadRequestException;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import io.enmasse.address.model.AddressSpace;
 import io.enmasse.api.auth.RbacSecurityContext;
 import io.enmasse.api.auth.ResourceVerb;
@@ -19,22 +51,10 @@ import io.enmasse.k8s.model.v1beta1.TableRow;
 import io.enmasse.k8s.util.TimeUtil;
 import io.enmasse.user.api.UserApi;
 import io.enmasse.user.model.v1.User;
+import io.enmasse.user.model.v1.UserBuilder;
 import io.enmasse.user.model.v1.UserList;
-import io.enmasse.user.model.v1.UserMetadata;
 import io.fabric8.kubernetes.api.model.ListMeta;
 import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.validation.constraints.NotNull;
-import javax.ws.rs.*;
-import javax.ws.rs.core.*;
-import java.time.Clock;
-import java.time.Duration;
-import java.time.Instant;
-import java.util.*;
-import java.util.concurrent.Callable;
-import java.util.stream.Collectors;
 
 @Path(HttpUserService.BASE_URI)
 public class HttpUserService {
@@ -77,9 +97,9 @@ public class HttpUserService {
             UserList userList = new UserList();
             if (labelSelector != null) {
                 Map<String, String> labels = AddressApiHelper.parseLabelSelector(labelSelector);
-                userList.addAll(userApi.listUsersWithLabels(namespace, labels));
+                userList.getItems().addAll(userApi.listUsersWithLabels(namespace, labels).getItems());
             } else {
-                userList.addAll(userApi.listUsers(namespace));
+                userList.getItems().addAll(userApi.listUsers(namespace).getItems());
             }
             return Response.ok(formatResponse(acceptHeader, userList)).build();
         });
@@ -150,9 +170,9 @@ public class HttpUserService {
 
     private User setUserDefaults(User user, String namespace) {
         if (user.getMetadata().getNamespace() == null) {
-            user = new User.Builder(user)
-                    .setMetadata(new UserMetadata.Builder(user.getMetadata())
-                            .setNamespace(namespace)
+            user = new UserBuilder(user)
+                    .withMetadata(new ObjectMetaBuilder(user.getMetadata())
+                            .withNamespace(namespace)
                             .build())
                     .build();
         }
@@ -266,7 +286,7 @@ public class HttpUserService {
     private Object formatResponse(String headerParam, User user) {
         if (isTableFormat(headerParam)) {
             UserList list = new UserList();
-            list.add(user);
+            list.getItems().add(user);
             return new Table(new ListMeta(), tableColumnDefinitions, createRows(list));
         } else {
             return user;
diff --git a/k8s-api/pom.xml b/k8s-api/pom.xml
index 4dff9b3d7..dba6833c5 100644
--- a/k8s-api/pom.xml
+++ b/k8s-api/pom.xml
@@ -12,8 +12,7 @@
   <dependencies>
     <dependency>
       <groupId>io.enmasse</groupId>
-      <artifactId>address-model-lib</artifactId>
-      <scope>compile</scope>
+      <artifactId>api-model</artifactId>
     </dependency>
     <dependency>
       <groupId>io.fabric8</groupId>
diff --git a/k8s-api/src/main/java/io/enmasse/k8s/api/KubeSchemaApi.java b/k8s-api/src/main/java/io/enmasse/k8s/api/KubeSchemaApi.java
index b1fbb9755..c636edefe 100644
--- a/k8s-api/src/main/java/io/enmasse/k8s/api/KubeSchemaApi.java
+++ b/k8s-api/src/main/java/io/enmasse/k8s/api/KubeSchemaApi.java
@@ -48,13 +48,13 @@ public class KubeSchemaApi implements SchemaApi {
     }
 
     public static KubeSchemaApi create(NamespacedOpenShiftClient openShiftClient, String namespace, boolean isOpenShift) {
-        AddressSpacePlanApi addressSpacePlanApi = new KubeAddressSpacePlanApi(openShiftClient, namespace, AdminCrd.addressspaceplans());
+        AddressSpacePlanApi addressSpacePlanApi = new KubeAddressSpacePlanApi(openShiftClient, namespace, AdminCrd.addressSpacePlans());
 
-        AddressPlanApi addressPlanApi = new KubeAddressPlanApi(openShiftClient, namespace, AdminCrd.addressplans());
+        AddressPlanApi addressPlanApi = new KubeAddressPlanApi(openShiftClient, namespace, AdminCrd.addressPlans());
 
-        BrokeredInfraConfigApi brokeredInfraConfigApi = new KubeBrokeredInfraConfigApi(openShiftClient, namespace, AdminCrd.brokeredinfraconfigs());
+        BrokeredInfraConfigApi brokeredInfraConfigApi = new KubeBrokeredInfraConfigApi(openShiftClient, namespace, AdminCrd.brokeredInfraConfigs());
 
-        StandardInfraConfigApi standardInfraConfigApi = new KubeStandardInfraConfigApi(openShiftClient, namespace, AdminCrd.standardinfraconfigs());
+        StandardInfraConfigApi standardInfraConfigApi = new KubeStandardInfraConfigApi(openShiftClient, namespace, AdminCrd.standardInfraConfigs());
 
         Clock clock = Clock.systemUTC();
 
diff --git a/keycloak-controller/src/main/java/io/enmasse/keycloak/controller/KeycloakManager.java b/keycloak-controller/src/main/java/io/enmasse/keycloak/controller/KeycloakManager.java
index aebead415..96ade36e2 100644
--- a/keycloak-controller/src/main/java/io/enmasse/keycloak/controller/KeycloakManager.java
+++ b/keycloak-controller/src/main/java/io/enmasse/keycloak/controller/KeycloakManager.java
@@ -10,6 +10,8 @@ import io.enmasse.config.AnnotationKeys;
 import io.enmasse.k8s.api.Watcher;
 import io.enmasse.user.api.UserApi;
 import io.enmasse.user.model.v1.*;
+import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -108,25 +110,25 @@ public class KeycloakManager implements Watcher<AddressSpace>
             } else {
                 String consoleUri = getConsoleUri(endpointStatus);
                 keycloak.createRealm(addressSpace.getNamespace(), realmName, consoleUri, keycloakRealmParams);
-                userApi.createUser(realmName, new User.Builder()
-                        .setMetadata(new UserMetadata.Builder()
-                                .setName(addressSpace.getName() + "." + KubeUtil.sanitizeUserName(userName))
-                                .setNamespace(addressSpace.getNamespace())
+                userApi.createUser(realmName, new UserBuilder()
+                        .withMetadata(new ObjectMetaBuilder()
+                                .withName(addressSpace.getName() + "." + KubeUtil.sanitizeUserName(userName))
+                                .withNamespace(addressSpace.getNamespace())
                                 .build())
-                        .setSpec(new UserSpec.Builder()
-                                .setUsername(KubeUtil.sanitizeUserName(userName))
-                                .setAuthentication(new UserAuthentication.Builder()
-                                        .setType(UserAuthenticationType.federated)
-                                        .setProvider("openshift")
-                                        .setFederatedUserid(userId)
-                                        .setFederatedUsername(userName)
+                        .withSpec(new UserSpecBuilder()
+                                .withUsername(KubeUtil.sanitizeUserName(userName))
+                                .withAuthentication(new UserAuthenticationBuilder()
+                                        .withType(UserAuthenticationType.federated)
+                                        .withProvider("openshift")
+                                        .withFederatedUserid(userId)
+                                        .withFederatedUsername(userName)
                                         .build())
-                                .setAuthorization(Arrays.asList(new UserAuthorization.Builder()
-                                                .setAddresses(Collections.singletonList("*"))
-                                                .setOperations(Arrays.asList(send, recv, view))
+                                .withAuthorization(Arrays.asList(new UserAuthorizationBuilder()
+                                                .withAddresses(Collections.singletonList("*"))
+                                                .withOperations(Arrays.asList(send, recv, view))
                                                 .build(),
-                                        new UserAuthorization.Builder()
-                                                .setOperations(Collections.singletonList(Operation.manage))
+                                        new UserAuthorizationBuilder()
+                                                .withOperations(Collections.singletonList(Operation.manage))
                                                 .build()))
                                 .build())
                         .build());
diff --git a/keycloak-user-api/pom.xml b/keycloak-user-api/pom.xml
index f104093d4..44ba19fbf 100644
--- a/keycloak-user-api/pom.xml
+++ b/keycloak-user-api/pom.xml
@@ -12,8 +12,7 @@
   <dependencies>
     <dependency>
       <groupId>io.enmasse</groupId>
-      <artifactId>user-api</artifactId>
-      <scope>compile</scope>
+      <artifactId>api-model</artifactId>
     </dependency>
     <dependency>
       <groupId>io.enmasse</groupId>
diff --git a/keycloak-user-api/src/main/java/io/enmasse/user/keycloak/KeycloakUserApi.java b/keycloak-user-api/src/main/java/io/enmasse/user/keycloak/KeycloakUserApi.java
index 4b33217cb..0aab607b1 100644
--- a/keycloak-user-api/src/main/java/io/enmasse/user/keycloak/KeycloakUserApi.java
+++ b/keycloak-user-api/src/main/java/io/enmasse/user/keycloak/KeycloakUserApi.java
@@ -4,20 +4,6 @@
  */
 package io.enmasse.user.keycloak;
 
-import org.keycloak.admin.client.CreatedResponseUtil;
-import org.keycloak.admin.client.Keycloak;
-import org.keycloak.admin.client.resource.RealmResource;
-import org.keycloak.admin.client.resource.UserResource;
-import org.keycloak.representations.idm.CredentialRepresentation;
-import org.keycloak.representations.idm.FederatedIdentityRepresentation;
-import org.keycloak.representations.idm.GroupRepresentation;
-import org.keycloak.representations.idm.RealmRepresentation;
-import org.keycloak.representations.idm.UserRepresentation;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.Response;
 import java.io.UnsupportedEncodingException;
 import java.net.URLDecoder;
 import java.net.URLEncoder;
@@ -36,16 +22,34 @@ import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
 
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+
+import org.keycloak.admin.client.CreatedResponseUtil;
+import org.keycloak.admin.client.Keycloak;
+import org.keycloak.admin.client.resource.RealmResource;
+import org.keycloak.admin.client.resource.UserResource;
+import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.representations.idm.FederatedIdentityRepresentation;
+import org.keycloak.representations.idm.GroupRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import io.enmasse.k8s.util.TimeUtil;
 import io.enmasse.user.api.UserApi;
 import io.enmasse.user.model.v1.Operation;
 import io.enmasse.user.model.v1.User;
 import io.enmasse.user.model.v1.UserAuthentication;
+import io.enmasse.user.model.v1.UserAuthenticationBuilder;
 import io.enmasse.user.model.v1.UserAuthenticationType;
 import io.enmasse.user.model.v1.UserAuthorization;
+import io.enmasse.user.model.v1.UserAuthorizationBuilder;
+import io.enmasse.user.model.v1.UserBuilder;
 import io.enmasse.user.model.v1.UserList;
-import io.enmasse.user.model.v1.UserMetadata;
-import io.enmasse.user.model.v1.UserSpec;
+import io.enmasse.user.model.v1.UserSpecBuilder;
+import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
 
 public class KeycloakUserApi implements UserApi {
 
@@ -408,7 +412,7 @@ public class KeycloakUserApi implements UserApi {
                     List<UserRepresentation> userReps = keycloak.realm(realm).users().list();
                     for (UserRepresentation userRep : userReps) {
                         List<GroupRepresentation> groupReps = keycloak.realm(realm).users().get(userRep.getId()).groups();
-                        userList.add(buildUser(userRep, groupReps));
+                        userList.getItems().add(buildUser(userRep, groupReps));
                     }
                 }
             }
@@ -451,28 +455,28 @@ public class KeycloakUserApi implements UserApi {
 
         List<UserAuthorization> authorizations = new ArrayList<>();
         for (Map.Entry<Set<Operation>, Set<String>> operationsEntry : operations.entrySet()) {
-            authorizations.add(new UserAuthorization.Builder()
-                    .setAddresses(new ArrayList<>(operationsEntry.getValue()))
-                    .setOperations(new ArrayList<>(operationsEntry.getKey()))
+            authorizations.add(new UserAuthorizationBuilder()
+                    .withAddresses(new ArrayList<>(operationsEntry.getValue()))
+                    .withOperations(new ArrayList<>(operationsEntry.getKey()))
                     .build());
         }
 
         String name = userRep.getAttributes().get("resourceName").get(0);
         String namespace = userRep.getAttributes().get("resourceNamespace").get(0);
 
-        return new User.Builder()
-                .setMetadata(new UserMetadata.Builder()
-                        .setName(name)
-                        .setNamespace(namespace)
-                        .setSelfLink("/apis/user.enmasse.io/v1alpha1/namespaces/" + namespace + "/messagingusers/" + name)
-                        .setCreationTimestamp(userRep.getAttributes().get("creationTimestamp").get(0))
+        return new UserBuilder()
+                .withMetadata(new ObjectMetaBuilder()
+                        .withName(name)
+                        .withNamespace(namespace)
+                        .withSelfLink("/apis/user.enmasse.io/v1alpha1/namespaces/" + namespace + "/messagingusers/" + name)
+                        .withCreationTimestamp(userRep.getAttributes().get("creationTimestamp").get(0))
                         .build())
-                .setSpec(new UserSpec.Builder()
-                        .setUsername(userRep.getUsername())
-                        .setAuthentication(new UserAuthentication.Builder()
-                                .setType(UserAuthenticationType.valueOf(userRep.getAttributes().get("authenticationType").get(0)))
+                .withSpec(new UserSpecBuilder()
+                        .withUsername(userRep.getUsername())
+                        .withAuthentication(new UserAuthenticationBuilder()
+                                .withType(UserAuthenticationType.valueOf(userRep.getAttributes().get("authenticationType").get(0)))
                                 .build())
-                        .setAuthorization(authorizations)
+                        .withAuthorization(authorizations)
                         .build())
                 .build();
     }
@@ -499,7 +503,7 @@ public class KeycloakUserApi implements UserApi {
 
                     for (UserRepresentation userRep : userReps) {
                         List<GroupRepresentation> groupReps = keycloak.realm(realm).users().get(userRep.getId()).groups();
-                        userList.add(buildUser(userRep, groupReps));
+                        userList.getItems().add(buildUser(userRep, groupReps));
                     }
                 }
             }
diff --git a/pom.xml b/pom.xml
index 3a53bf968..5ef01be07 100644
--- a/pom.xml
+++ b/pom.xml
@@ -97,8 +97,7 @@
     </properties>
 
     <modules>
-        <module>address-model-lib</module>
-        <module>user-api</module>
+        <module>api-model</module>
         <module>metrics-api</module>
         <module>keycloak-user-api</module>
         <module>agent</module>
@@ -134,7 +133,7 @@
             </dependency>
             <dependency>
                 <groupId>io.enmasse</groupId>
-                <artifactId>address-model-lib</artifactId>
+                <artifactId>api-model</artifactId>
                 <version>${project.version}</version>
             </dependency>
             <dependency>
@@ -157,11 +156,6 @@
                 <artifactId>k8s-api</artifactId>
                 <version>${project.version}</version>
             </dependency>
-            <dependency>
-                <groupId>io.enmasse</groupId>
-                <artifactId>user-api</artifactId>
-                <version>${project.version}</version>
-            </dependency>
             <dependency>
                 <groupId>io.enmasse</groupId>
                 <artifactId>metrics-api</artifactId>
diff --git a/service-broker/pom.xml b/service-broker/pom.xml
index 7a8a29132..06e3a0411 100644
--- a/service-broker/pom.xml
+++ b/service-broker/pom.xml
@@ -11,8 +11,7 @@
   <dependencies>
     <dependency>
       <groupId>io.enmasse</groupId>
-      <artifactId>address-model-lib</artifactId>
-      <scope>compile</scope>
+      <artifactId>api-model</artifactId>
     </dependency>
     <dependency>
       <groupId>io.enmasse</groupId>
diff --git a/service-broker/src/main/java/io/enmasse/osb/api/bind/OSBBindingService.java b/service-broker/src/main/java/io/enmasse/osb/api/bind/OSBBindingService.java
index 6332f10b6..d26342e78 100644
--- a/service-broker/src/main/java/io/enmasse/osb/api/bind/OSBBindingService.java
+++ b/service-broker/src/main/java/io/enmasse/osb/api/bind/OSBBindingService.java
@@ -17,6 +17,7 @@ import io.enmasse.osb.api.EmptyResponse;
 import io.enmasse.osb.api.OSBServiceBase;
 import io.enmasse.user.api.UserApi;
 import io.enmasse.user.model.v1.*;
+import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
 
 import javax.ws.rs.*;
 import javax.ws.rs.core.Context;
@@ -102,34 +103,34 @@ public class OSBBindingService extends OSBServiceBase {
     }
 
     private User createOrReplaceUser(AddressSpace addressSpace, String username, String password, Map<String, String> parameters) throws Exception {
-        UserSpec.Builder specBuilder = new UserSpec.Builder();
-        specBuilder.setUsername(username);
-        specBuilder.setAuthentication(new UserAuthentication.Builder()
-                .setType(UserAuthenticationType.password)
-                .setPassword(Base64.getEncoder().encodeToString(password.getBytes(StandardCharsets.UTF_8)))
+        UserSpecBuilder specBuilder = new UserSpecBuilder();
+        specBuilder.withUsername(username);
+        specBuilder.withAuthentication(new UserAuthenticationBuilder()
+                .withType(UserAuthenticationType.password)
+                .withPassword(Base64.getEncoder().encodeToString(password.getBytes(StandardCharsets.UTF_8)))
                 .build());
 
 
         List<UserAuthorization> authorizations = new ArrayList<>();
 
-        authorizations.add(new UserAuthorization.Builder()
-                .setOperations(Arrays.asList(Operation.send))
-                .setAddresses(getAddresses(parameters.get("sendAddresses")))
+        authorizations.add(new UserAuthorizationBuilder()
+                .withOperations(Arrays.asList(Operation.send))
+                .withAddresses(getAddresses(parameters.get("sendAddresses")))
                 .build());
 
-        authorizations.add(new UserAuthorization.Builder()
-                .setOperations(Arrays.asList(Operation.recv))
-                .setAddresses(getAddresses(parameters.get("receiveAddresses")))
+        authorizations.add(new UserAuthorizationBuilder()
+                .withOperations(Arrays.asList(Operation.recv))
+                .withAddresses(getAddresses(parameters.get("receiveAddresses")))
                 .build());
 
-        specBuilder.setAuthorization(authorizations);
+        specBuilder.withAuthorization(authorizations);
 
-        User user = new User.Builder()
-            .setMetadata(new UserMetadata.Builder()
-                    .setNamespace(addressSpace.getNamespace())
-                    .setName(addressSpace.getName() + "." + username)
+        User user = new UserBuilder()
+            .withMetadata(new ObjectMetaBuilder()
+                    .withNamespace(addressSpace.getNamespace())
+                    .withName(addressSpace.getName() + "." + username)
                     .build())
-                        .setSpec(specBuilder.build())
+                        .withSpec(specBuilder.build())
                         .build();
 
         String realmName = addressSpace.getAnnotation(AnnotationKeys.REALM_NAME);
@@ -154,8 +155,8 @@ public class OSBBindingService extends OSBServiceBase {
         return builder.toString();
     }
 
-    private Collection<String> getAddresses(String addressList) {
-        Set<String> groups = new HashSet<>();
+    private List<String> getAddresses(String addressList) {
+        final Set<String> groups = new HashSet<>();
         if(addressList != null) {
             for(String address : addressList.split(",")) {
                 address = address.trim();
@@ -164,7 +165,7 @@ public class OSBBindingService extends OSBServiceBase {
                 }
             }
         }
-        return groups;
+        return new ArrayList<>(groups);
     }
 
     @DELETE
diff --git a/standard-controller/pom.xml b/standard-controller/pom.xml
index 3280410b8..d784b5b4e 100644
--- a/standard-controller/pom.xml
+++ b/standard-controller/pom.xml
@@ -11,8 +11,7 @@
   <dependencies>
     <dependency>
       <groupId>io.enmasse</groupId>
-      <artifactId>address-model-lib</artifactId>
-      <scope>compile</scope>
+      <artifactId>api-model</artifactId>
     </dependency>
     <dependency>
       <groupId>io.enmasse</groupId>
diff --git a/templates/address-space-controller/020-ConfigMap-address-space-definitions.yaml b/templates/address-space-controller/020-ConfigMap-address-space-definitions.yaml
index 0230d0390..892a39cf8 100644
--- a/templates/address-space-controller/020-ConfigMap-address-space-definitions.yaml
+++ b/templates/address-space-controller/020-ConfigMap-address-space-definitions.yaml
@@ -1096,7 +1096,7 @@ data:
               - name: AMQ_NAME
                 value: serverData
               - name: HOME
-                value: /run/artemis/split-1/
+                value: /var/run/artemis/split-1/
               image: ${ARTEMIS_IMAGE}
               imagePullPolicy: ${IMAGE_PULL_POLICY}
               command:
@@ -1162,7 +1162,7 @@ data:
               - name: AMQ_NAME
                 value: serverData
               - name: HOME
-                value: /run/artemis/split-1/
+                value: /var/run/artemis/split-1/
               image: ${ARTEMIS_PLUGIN_IMAGE}
               name: broker-plugin
               volumeMounts:
diff --git a/templates/address-space-controller/020-ConfigMap-standard-broker-definitions.yaml b/templates/address-space-controller/020-ConfigMap-standard-broker-definitions.yaml
index 6a305ea86..3b0d2bde1 100644
--- a/templates/address-space-controller/020-ConfigMap-standard-broker-definitions.yaml
+++ b/templates/address-space-controller/020-ConfigMap-standard-broker-definitions.yaml
@@ -113,7 +113,7 @@ data:
               - name: AMQ_NAME
                 value: serverData
               - name: HOME
-                value: /run/artemis/split-1/
+                value: /var/run/artemis/split-1/
               image: ${ARTEMIS_IMAGE}
               imagePullPolicy: ${IMAGE_PULL_POLICY}
               command:
@@ -187,7 +187,7 @@ data:
               - name: AMQ_NAME
                 value: serverData
               - name: HOME
-                value: /run/artemis/split-1/
+                value: /var/run/artemis/split-1/
               image: ${ARTEMIS_PLUGIN_IMAGE}
               name: broker-plugin
               volumeMounts:
@@ -385,7 +385,7 @@ data:
               - name: AMQ_NAME
                 value: serverData
               - name: HOME
-                value: /run/artemis/split-1/
+                value: /var/run/artemis/split-1/
               image: ${ARTEMIS_IMAGE}
               imagePullPolicy: ${IMAGE_PULL_POLICY}
               command:
@@ -488,7 +488,7 @@ data:
               - name: AMQ_NAME
                 value: serverData
               - name: HOME
-                value: /run/artemis/split-1/
+                value: /var/run/artemis/split-1/
               image: ${ARTEMIS_PLUGIN_IMAGE}
               name: broker-plugin
               volumeMounts:
diff --git a/user-api/pom.xml b/user-api/pom.xml
deleted file mode 100644
index ef420f4a9..000000000
--- a/user-api/pom.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
-    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
-  <parent>
-    <groupId>io.enmasse</groupId>
-    <artifactId>enmasse</artifactId>
-    <version>0.25-SNAPSHOT</version>
-  </parent>
-  <modelVersion>4.0.0</modelVersion>
-  <groupId>io.enmasse</groupId>
-  <artifactId>user-api</artifactId>
-  <dependencies>
-    <dependency>
-      <groupId>com.fasterxml.jackson.core</groupId>
-      <artifactId>jackson-core</artifactId>
-      <scope>compile</scope>
-    </dependency>
-    <dependency>
-      <groupId>com.fasterxml.jackson.core</groupId>
-      <artifactId>jackson-databind</artifactId>
-      <scope>compile</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.junit.jupiter</groupId>
-      <artifactId>junit-jupiter-api</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.junit.jupiter</groupId>
-      <artifactId>junit-jupiter-engine</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.junit.platform</groupId>
-      <artifactId>junit-platform-launcher</artifactId>
-      <scope>test</scope>
-    </dependency>
-  </dependencies>
-</project>
diff --git a/user-api/src/main/java/io/enmasse/user/model/v1/User.java b/user-api/src/main/java/io/enmasse/user/model/v1/User.java
deleted file mode 100644
index d32b5d260..000000000
--- a/user-api/src/main/java/io/enmasse/user/model/v1/User.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2017-2018, EnMasse authors.
- * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
- */
-package io.enmasse.user.model.v1;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-import java.util.Objects;
-
-@JsonInclude(JsonInclude.Include.NON_NULL)
-public class User {
-    @JsonProperty("apiVersion")
-    private final String apiVersion = "user.enmasse.io/v1alpha1";
-    @JsonProperty("kind")
-    private final String kind = "MessagingUser";
-
-    private final UserMetadata metadata;
-    private final UserSpec spec;
-
-    @JsonCreator
-    public User(@JsonProperty("metadata") UserMetadata metadata,
-                @JsonProperty("spec") UserSpec spec) {
-        this.metadata = metadata;
-        this.spec = spec;
-    }
-
-    public UserMetadata getMetadata() {
-        return metadata;
-    }
-
-    public UserSpec getSpec() {
-        return spec;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-        User user = (User) o;
-        return Objects.equals(apiVersion, user.apiVersion) &&
-                Objects.equals(kind, user.kind) &&
-                Objects.equals(metadata, user.metadata);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(apiVersion, kind, metadata);
-    }
-
-    public void validate() {
-        try {
-            Objects.requireNonNull(metadata, "'metadata' must be set");
-            Objects.requireNonNull(spec, "'spec' must be set");
-
-            metadata.validate();
-            spec.validate();
-        } catch (Exception e) {
-            throw new UserValidationFailedException(e);
-        }
-    }
-
-    public static class Builder {
-        private UserMetadata metadata;
-        private UserSpec spec;
-
-        public Builder() { }
-
-        public Builder(User user) {
-            this.metadata = user.getMetadata();
-            this.spec = user.getSpec();
-        }
-
-        public Builder setMetadata(UserMetadata metadata) {
-            this.metadata = metadata;
-            return this;
-        }
-
-        public Builder setSpec(UserSpec spec) {
-            this.spec = spec;
-            return this;
-        }
-
-        public User build() {
-            Objects.requireNonNull(metadata);
-            Objects.requireNonNull(spec);
-            return new User(metadata, spec);
-        }
-    }
-}
diff --git a/user-api/src/main/java/io/enmasse/user/model/v1/UserList.java b/user-api/src/main/java/io/enmasse/user/model/v1/UserList.java
deleted file mode 100644
index 44b5a31df..000000000
--- a/user-api/src/main/java/io/enmasse/user/model/v1/UserList.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2017-2018, EnMasse authors.
- * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
- */
-package io.enmasse.user.model.v1;
-
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@JsonInclude(JsonInclude.Include.NON_NULL)
-public class UserList {
-    @JsonProperty("apiVersion")
-    private final String apiVersion = "user.enmasse.io/v1alpha1";
-    @JsonProperty("kind")
-    private final String kind = "MessagingUserList";
-
-    @JsonProperty("items")
-    private final List<User> items;
-
-    public UserList() {
-        items = new ArrayList<>();
-    }
-
-    public UserList(List<User> items) {
-        this.items = items;
-    }
-
-    public void add(User user) {
-        items.add(user);
-    }
-
-    public List<User> getItems() {
-        return items;
-    }
-
-    public void addAll(UserList userList) {
-        this.items.addAll(userList.getItems());
-    }
-}
diff --git a/user-api/src/main/java/io/enmasse/user/model/v1/UserMetadata.java b/user-api/src/main/java/io/enmasse/user/model/v1/UserMetadata.java
deleted file mode 100644
index 337673f92..000000000
--- a/user-api/src/main/java/io/enmasse/user/model/v1/UserMetadata.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright 2017-2018, EnMasse authors.
- * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
- */
-package io.enmasse.user.model.v1;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-import java.util.Objects;
-import java.util.regex.Pattern;
-
-@JsonInclude(JsonInclude.Include.NON_NULL)
-public class UserMetadata {
-    private final String name;
-    private final String namespace;
-    private final String creationTimestamp;
-    private final String selfLink;
-    private final String resourceVersion;
-
-    private final Pattern namePattern = Pattern.compile("^[a-z]+([a-z0-9\\-]*[a-z0-9]+|[a-z0-9]*)\\.[a-z0-9]+([a-z0-9@.\\-]*[a-z0-9]+|[a-z0-9]*)$");
-
-    @JsonCreator
-    public UserMetadata(@JsonProperty("name") String name,
-                        @JsonProperty("namespace") String namespace,
-                        @JsonProperty("creationTimestamp") String creationTimestamp,
-                        @JsonProperty("selfLink") String selfLink,
-                        @JsonProperty("resourceVersion") String resourceVersion) {
-        this.name = name;
-        this.namespace = namespace;
-        this.creationTimestamp = creationTimestamp;
-        this.selfLink = selfLink;
-        this.resourceVersion = resourceVersion;
-    }
-
-    public String getName() {
-        return name;
-    }
-
-    public String getNamespace() {
-        return namespace;
-    }
-
-    public String getCreationTimestamp() {
-        return creationTimestamp;
-    }
-
-    public String getSelfLink() {
-        return selfLink;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-        UserMetadata that = (UserMetadata) o;
-        return Objects.equals(name, that.name) &&
-                Objects.equals(namespace, that.namespace);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(name, namespace);
-    }
-
-    public void validate() {
-        Objects.requireNonNull(name, "'name' must be set");
-        if (!namePattern.matcher(name).matches()) {
-            throw new UserValidationFailedException("Invalid resource name '" + name + "', must match " + namePattern);
-        }
-        Objects.requireNonNull(namespace, "'namespace' must be set");
-    }
-
-    public String getResourceVersion() {
-        return resourceVersion;
-    }
-
-    public static class Builder {
-        private String name;
-        private String namespace;
-        private String creationTimestamp;
-        private String selfLink;
-        private String resourceVersion;
-
-        public Builder() { }
-
-        public Builder(UserMetadata userMetadata) {
-            this.name = userMetadata.getName();
-            this.namespace = userMetadata.getNamespace();
-            this.creationTimestamp = userMetadata.getCreationTimestamp();
-            this.selfLink = userMetadata.getSelfLink();
-            this.resourceVersion = userMetadata.getResourceVersion();
-        }
-
-        public Builder setName(String name) {
-            this.name = name;
-            return this;
-        }
-
-        public Builder setNamespace(String namespace) {
-            this.namespace = namespace;
-            return this;
-        }
-
-        public Builder setCreationTimestamp(String creationTimestamp) {
-            this.creationTimestamp = creationTimestamp;
-            return this;
-        }
-
-        public Builder setSelfLink(String selfLink) {
-            this.selfLink = selfLink;
-            return this;
-        }
-
-        public Builder setResourceVersion(String resourceVersion) {
-            this.resourceVersion = resourceVersion;
-            return this;
-        }
-
-        public UserMetadata build() {
-            Objects.requireNonNull(name);
-            Objects.requireNonNull(namespace);
-            return new UserMetadata(name, namespace, creationTimestamp, selfLink, resourceVersion);
-        }
-    }
-}


Test patch:
diff --git a/address-model-lib/src/test/java/io/enmasse/address/model/AddressSpaceTest.java b/api-model/src/test/java/io/enmasse/address/model/AddressSpaceTest.java
similarity index 94%
rename from address-model-lib/src/test/java/io/enmasse/address/model/AddressSpaceTest.java
rename to api-model/src/test/java/io/enmasse/address/model/AddressSpaceTest.java
index c9b10ce9f..12de1c16d 100644
--- a/address-model-lib/src/test/java/io/enmasse/address/model/AddressSpaceTest.java
+++ b/api-model/src/test/java/io/enmasse/address/model/AddressSpaceTest.java
@@ -40,7 +40,7 @@ public class AddressSpaceTest {
     @Test
     public void testSimpleWithMissingMandatory() {
         try {
-            AddressSpace space = new AddressSpace.Builder()
+            new AddressSpace.Builder()
                     .setType("type")
                     .setPlan("plan")
                     .build();
@@ -50,7 +50,7 @@ public class AddressSpaceTest {
         }
 
         try {
-            AddressSpace space = new AddressSpace.Builder()
+            new AddressSpace.Builder()
                     .setName("name")
                     .setPlan("plan")
                     .build();
@@ -60,7 +60,7 @@ public class AddressSpaceTest {
         }
 
         try {
-            AddressSpace space = new AddressSpace.Builder()
+            new AddressSpace.Builder()
                     .setName("name")
                     .setType("type")
                     .build();
diff --git a/address-model-lib/src/test/java/io/enmasse/address/model/v1/address/AddressTest.java b/api-model/src/test/java/io/enmasse/address/model/v1/address/AddressTest.java
similarity index 100%
rename from address-model-lib/src/test/java/io/enmasse/address/model/v1/address/AddressTest.java
rename to api-model/src/test/java/io/enmasse/address/model/v1/address/AddressTest.java
diff --git a/address-model-lib/src/test/java/io/enmasse/address/model/v1/address/KubeUtilTest.java b/api-model/src/test/java/io/enmasse/address/model/v1/address/KubeUtilTest.java
similarity index 100%
rename from address-model-lib/src/test/java/io/enmasse/address/model/v1/address/KubeUtilTest.java
rename to api-model/src/test/java/io/enmasse/address/model/v1/address/KubeUtilTest.java
diff --git a/address-model-lib/src/test/java/io/enmasse/address/model/v1/address/SerializationTest.java b/api-model/src/test/java/io/enmasse/address/model/v1/address/SerializationTest.java
similarity index 99%
rename from address-model-lib/src/test/java/io/enmasse/address/model/v1/address/SerializationTest.java
rename to api-model/src/test/java/io/enmasse/address/model/v1/address/SerializationTest.java
index cdf0d7b63..d45dbaa80 100644
--- a/address-model-lib/src/test/java/io/enmasse/address/model/v1/address/SerializationTest.java
+++ b/api-model/src/test/java/io/enmasse/address/model/v1/address/SerializationTest.java
@@ -114,6 +114,7 @@ public class SerializationTest {
         CodecV1.getMapper().readValue(serialized, AddressSpace.class);
     }
 
+    @SuppressWarnings("serial")
     @Test
     public void testSerializeAddressSpace() throws IOException {
         AddressSpace addressSpace = new AddressSpace.Builder()
diff --git a/address-model-lib/src/test/java/io/enmasse/admin/model/v1/InfraConfigDeserializerTest.java b/api-model/src/test/java/io/enmasse/admin/model/v1/InfraConfigDeserializerTest.java
similarity index 100%
rename from address-model-lib/src/test/java/io/enmasse/admin/model/v1/InfraConfigDeserializerTest.java
rename to api-model/src/test/java/io/enmasse/admin/model/v1/InfraConfigDeserializerTest.java
diff --git a/user-api/src/test/java/io/enmasse/user/model/v1/UserModelTest.java b/api-model/src/test/java/io/enmasse/user/model/v1/UserModelTest.java
similarity index 70%
rename from user-api/src/test/java/io/enmasse/user/model/v1/UserModelTest.java
rename to api-model/src/test/java/io/enmasse/user/model/v1/UserModelTest.java
index f122a36b8..56554a5dc 100644
--- a/user-api/src/test/java/io/enmasse/user/model/v1/UserModelTest.java
+++ b/api-model/src/test/java/io/enmasse/user/model/v1/UserModelTest.java
@@ -5,6 +5,9 @@
 package io.enmasse.user.model.v1;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
+
+import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
+
 import org.junit.jupiter.api.Test;
 
 import java.io.IOException;
@@ -19,25 +22,25 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 public class UserModelTest {
     @Test
     public void testSerializeUserPassword() throws IOException {
-        User user = new User.Builder()
-                .setMetadata(new UserMetadata.Builder()
-                        .setName("myspace.user1")
-                        .setNamespace("ns1")
+        User user = new UserBuilder()
+                .withMetadata(new ObjectMetaBuilder()
+                        .withName("myspace.user1")
+                        .withNamespace("ns1")
                         .build())
-                .setSpec(new UserSpec.Builder()
-                        .setUsername("user1")
-                        .setAuthentication(new UserAuthentication.Builder()
-                                .setType(UserAuthenticationType.password)
-                                .setPassword("p4ssw0rd")
+                .withSpec(new UserSpecBuilder()
+                        .withUsername("user1")
+                        .withAuthentication(new UserAuthenticationBuilder()
+                                .withType(UserAuthenticationType.password)
+                                .withPassword("p4ssw0rd")
                                 .build())
-                        .setAuthorization(Arrays.asList(
-                                new UserAuthorization.Builder()
-                                        .setAddresses(Arrays.asList("queue1", "topic1"))
-                                        .setOperations(Arrays.asList(Operation.send, Operation.recv))
+                        .withAuthorization(Arrays.asList(
+                                new UserAuthorizationBuilder()
+                                        .withAddresses(Arrays.asList("queue1", "topic1"))
+                                        .withOperations(Arrays.asList(Operation.send, Operation.recv))
                                         .build(),
-                                new UserAuthorization.Builder()
-                                        .setAddresses(Arrays.asList("direct*"))
-                                        .setOperations(Arrays.asList(Operation.view))
+                                new UserAuthorizationBuilder()
+                                        .withAddresses(Arrays.asList("direct*"))
+                                        .withOperations(Arrays.asList(Operation.view))
                                         .build()))
                         .build())
                 .build();
@@ -57,7 +60,7 @@ public class UserModelTest {
         assertAuthorization(deserialized, Arrays.asList("queue1", "topic1"), Arrays.asList(Operation.send, Operation.recv));
 
         UserList list = new UserList();
-        list.add(user);
+        list.getItems().add(user);
 
         serialized = mapper.writeValueAsBytes(list);
         UserList deserializedList = mapper.readValue(serialized, UserList.class);
@@ -78,27 +81,27 @@ public class UserModelTest {
 
     @Test
     public void testSerializeUserFederated() throws IOException {
-        User user = new User.Builder()
-                .setMetadata(new UserMetadata.Builder()
-                        .setName("myspace.user1")
-                        .setNamespace("ns1")
+        User user = new UserBuilder()
+                .withMetadata(new ObjectMetaBuilder()
+                        .withName("myspace.user1")
+                        .withNamespace("ns1")
                         .build())
-                .setSpec(new UserSpec.Builder()
-                        .setUsername("user1")
-                        .setAuthentication(new UserAuthentication.Builder()
-                                .setType(UserAuthenticationType.federated)
-                                .setProvider("openshift")
-                                .setFederatedUserid("uuid")
-                                .setFederatedUsername("user1")
+                .withSpec(new UserSpecBuilder()
+                        .withUsername("user1")
+                        .withAuthentication(new UserAuthenticationBuilder()
+                                .withType(UserAuthenticationType.federated)
+                                .withProvider("openshift")
+                                .withFederatedUserid("uuid")
+                                .withFederatedUsername("user1")
                                 .build())
-                        .setAuthorization(Arrays.asList(
-                                new UserAuthorization.Builder()
-                                        .setAddresses(Arrays.asList("queue1", "topic1"))
-                                        .setOperations(Arrays.asList(Operation.send, Operation.recv))
+                        .withAuthorization(Arrays.asList(
+                                new UserAuthorizationBuilder()
+                                        .withAddresses(Arrays.asList("queue1", "topic1"))
+                                        .withOperations(Arrays.asList(Operation.send, Operation.recv))
                                         .build(),
-                                new UserAuthorization.Builder()
-                                        .setAddresses(Arrays.asList("direct*"))
-                                        .setOperations(Arrays.asList(Operation.view))
+                                new UserAuthorizationBuilder()
+                                        .withAddresses(Arrays.asList("direct*"))
+                                        .withOperations(Arrays.asList(Operation.view))
                                         .build()))
                         .build())
                 .build();
@@ -118,7 +121,7 @@ public class UserModelTest {
         assertAuthorization(deserialized, Arrays.asList("queue1", "topic1"), Arrays.asList(Operation.send, Operation.recv));
 
         UserList list = new UserList();
-        list.add(user);
+        list.getItems().add(user);
 
         serialized = mapper.writeValueAsBytes(list);
         UserList deserializedList = mapper.readValue(serialized, UserList.class);
@@ -178,27 +181,27 @@ public class UserModelTest {
     }
 
     private void createAndValidate(String name, String username, boolean shouldValidate) {
-        User u1 = new User.Builder()
-                .setMetadata(new UserMetadata.Builder()
-                        .setName(name)
-                        .setNamespace("ns1")
+        User u1 = new UserBuilder()
+                .withMetadata(new ObjectMetaBuilder()
+                        .withName(name)
+                        .withNamespace("ns1")
                         .build())
-                .setSpec(new UserSpec.Builder()
-                        .setUsername(username)
-                        .setAuthentication(new UserAuthentication.Builder()
-                                .setType(UserAuthenticationType.federated)
-                                .setProvider("openshift")
-                                .setFederatedUserid("uuid")
-                                .setFederatedUsername("user1")
+                .withSpec(new UserSpecBuilder()
+                        .withUsername(username)
+                        .withAuthentication(new UserAuthenticationBuilder()
+                                .withType(UserAuthenticationType.federated)
+                                .withProvider("openshift")
+                                .withFederatedUserid("uuid")
+                                .withFederatedUsername("user1")
                                 .build())
-                        .setAuthorization(Arrays.asList(
-                                new UserAuthorization.Builder()
-                                        .setAddresses(Arrays.asList("queue1", "topic1"))
-                                        .setOperations(Arrays.asList(Operation.send, Operation.recv))
+                        .withAuthorization(Arrays.asList(
+                                new UserAuthorizationBuilder()
+                                        .withAddresses(Arrays.asList("queue1", "topic1"))
+                                        .withOperations(Arrays.asList(Operation.send, Operation.recv))
                                         .build(),
-                                new UserAuthorization.Builder()
-                                        .setAddresses(Arrays.asList("direct*"))
-                                        .setOperations(Arrays.asList(Operation.view))
+                                new UserAuthorizationBuilder()
+                                        .withAddresses(Arrays.asList("direct*"))
+                                        .withOperations(Arrays.asList(Operation.view))
                                         .build()))
                         .build())
                 .build();
diff --git a/api-server/src/test/java/io/enmasse/api/server/HTTPServerTest.java b/api-server/src/test/java/io/enmasse/api/server/HTTPServerTest.java
index 23e2ab0b2..df7e71893 100644
--- a/api-server/src/test/java/io/enmasse/api/server/HTTPServerTest.java
+++ b/api-server/src/test/java/io/enmasse/api/server/HTTPServerTest.java
@@ -13,6 +13,7 @@ import io.enmasse.k8s.api.TestAddressSpaceApi;
 import io.enmasse.metrics.api.Metrics;
 import io.enmasse.user.api.UserApi;
 import io.enmasse.user.model.v1.*;
+import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
 import io.vertx.core.Vertx;
 import io.vertx.core.http.HttpClient;
 import io.vertx.core.http.HttpClientOptions;
@@ -59,20 +60,20 @@ public class HTTPServerTest {
 
         UserApi userApi = mock(UserApi.class);
         UserList users = new UserList();
-        users.add(new User.Builder()
-                .setMetadata(new UserMetadata.Builder()
-                        .setName("myinstance.user1")
-                        .setNamespace("myinstance")
+        users.getItems().add(new UserBuilder()
+                .withMetadata(new ObjectMetaBuilder()
+                        .withName("myinstance.user1")
+                        .withNamespace("myinstance")
                         .build())
-                .setSpec(new UserSpec.Builder()
-                        .setUsername("user1")
-                        .setAuthentication(new UserAuthentication.Builder()
-                                .setType(UserAuthenticationType.password)
-                                .setPassword("admin")
+                .withSpec(new UserSpecBuilder()
+                        .withUsername("user1")
+                        .withAuthentication(new UserAuthenticationBuilder()
+                                .withType(UserAuthenticationType.password)
+                                .withPassword("admin")
                                 .build())
-                        .setAuthorization(Arrays.asList(new UserAuthorization.Builder()
-                                .setAddresses(Arrays.asList("queue1"))
-                                .setOperations(Arrays.asList(Operation.send, Operation.recv))
+                        .withAuthorization(Arrays.asList(new UserAuthorizationBuilder()
+                                .withAddresses(Arrays.asList("queue1"))
+                                .withOperations(Arrays.asList(Operation.send, Operation.recv))
                                 .build()))
                         .build())
                 .build());
diff --git a/api-server/src/test/java/io/enmasse/api/v1/http/HttpUserServiceTest.java b/api-server/src/test/java/io/enmasse/api/v1/http/HttpUserServiceTest.java
index 2a9ae753f..efe07d7ed 100644
--- a/api-server/src/test/java/io/enmasse/api/v1/http/HttpUserServiceTest.java
+++ b/api-server/src/test/java/io/enmasse/api/v1/http/HttpUserServiceTest.java
@@ -11,6 +11,8 @@ import io.enmasse.config.AnnotationKeys;
 import io.enmasse.k8s.api.TestAddressSpaceApi;
 import io.enmasse.k8s.model.v1beta1.Table;
 import io.enmasse.user.model.v1.*;
+import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
+
 import org.jboss.resteasy.spi.ResteasyUriInfo;
 import org.junit.Before;
 import org.junit.Test;
@@ -64,43 +66,43 @@ public class HttpUserServiceTest {
                 .setType("type1")
                 .setPlan("myplan")
                 .build());
-        u1 = new User.Builder()
-                .setMetadata(new UserMetadata.Builder()
-                        .setName("myspace.user1")
-                        .setNamespace("ns1")
+        u1 = new UserBuilder()
+                .withMetadata(new ObjectMetaBuilder()
+                        .withName("myspace.user1")
+                        .withNamespace("ns1")
                         .build())
-                .setSpec(new UserSpec.Builder()
-                        .setUsername("user1")
-                        .setAuthentication(new UserAuthentication.Builder()
-                                .setType(UserAuthenticationType.password)
-                                .setPassword("p4ssw0rd")
+                .withSpec(new UserSpecBuilder()
+                        .withUsername("user1")
+                        .withAuthentication(new UserAuthenticationBuilder()
+                                .withType(UserAuthenticationType.password)
+                                .withPassword("p4ssw0rd")
                                 .build())
-                        .setAuthorization(Arrays.asList(
-                                new UserAuthorization.Builder()
-                                        .setAddresses(Arrays.asList("queue1", "topic1"))
-                                        .setOperations(Arrays.asList(Operation.send, Operation.recv))
+                        .withAuthorization(Arrays.asList(
+                                new UserAuthorizationBuilder()
+                                        .withAddresses(Arrays.asList("queue1", "topic1"))
+                                        .withOperations(Arrays.asList(Operation.send, Operation.recv))
                                         .build(),
-                                new UserAuthorization.Builder()
-                                        .setAddresses(Arrays.asList("direct*"))
-                                        .setOperations(Arrays.asList(Operation.view))
+                                new UserAuthorizationBuilder()
+                                        .withAddresses(Arrays.asList("direct*"))
+                                        .withOperations(Arrays.asList(Operation.view))
                                         .build()))
                         .build())
                 .build();
 
-        u2 = new User.Builder()
-                .setMetadata(new UserMetadata.Builder()
-                        .setName("otherspace.user2")
-                        .setNamespace("ns2")
+        u2 = new UserBuilder()
+                .withMetadata(new ObjectMetaBuilder()
+                        .withName("otherspace.user2")
+                        .withNamespace("ns2")
                         .build())
-                .setSpec(new UserSpec.Builder()
-                        .setUsername("user2")
-                        .setAuthentication(new UserAuthentication.Builder()
-                                .setType(UserAuthenticationType.password)
-                                .setPassword("pswd")
+                .withSpec(new UserSpecBuilder()
+                        .withUsername("user2")
+                        .withAuthentication(new UserAuthenticationBuilder()
+                                .withType(UserAuthenticationType.password)
+                                .withPassword("pswd")
                                 .build())
-                        .setAuthorization(Arrays.asList(
-                                new UserAuthorization.Builder()
-                                        .setOperations(Arrays.asList(Operation.manage))
+                        .withAuthorization(Arrays.asList(
+                                new UserAuthorizationBuilder()
+                                        .withOperations(Arrays.asList(Operation.manage))
                                         .build()))
                         .build())
                 .build();
@@ -183,21 +185,21 @@ public class HttpUserServiceTest {
 
     @Test
     public void testCreate() {
-        User u3 = new User.Builder()
-                .setMetadata(new UserMetadata.Builder()
-                        .setName("myspace.user3")
-                        .setNamespace("ns1")
+        User u3 = new UserBuilder()
+                .withMetadata(new ObjectMetaBuilder()
+                        .withName("myspace.user3")
+                        .withNamespace("ns1")
                         .build())
-                .setSpec(new UserSpec.Builder()
-                        .setUsername("user3")
-                        .setAuthentication(new UserAuthentication.Builder()
-                                .setType(UserAuthenticationType.password)
-                                .setPassword("p4ssw0rd")
+                .withSpec(new UserSpecBuilder()
+                        .withUsername("user3")
+                        .withAuthentication(new UserAuthenticationBuilder()
+                                .withType(UserAuthenticationType.password)
+                                .withPassword("p4ssw0rd")
                                 .build())
-                        .setAuthorization(Arrays.asList(
-                                new UserAuthorization.Builder()
-                                        .setAddresses(Arrays.asList("queue1", "topic1"))
-                                        .setOperations(Arrays.asList(Operation.send, Operation.recv))
+                        .withAuthorization(Arrays.asList(
+                                new UserAuthorizationBuilder()
+                                        .withAddresses(Arrays.asList("queue1", "topic1"))
+                                        .withOperations(Arrays.asList(Operation.send, Operation.recv))
                                         .build()))
                         .build())
                 .build();
@@ -210,21 +212,21 @@ public class HttpUserServiceTest {
     @Test
     public void testCreateException() {
         userApi.throwException = true;
-        User u3 = new User.Builder()
-                .setMetadata(new UserMetadata.Builder()
-                        .setName("myspace.user3")
-                        .setNamespace("ns1")
+        User u3 = new UserBuilder()
+                .withMetadata(new ObjectMetaBuilder()
+                        .withName("myspace.user3")
+                        .withNamespace("ns1")
                         .build())
-                .setSpec(new UserSpec.Builder()
-                        .setUsername("user3")
-                        .setAuthentication(new UserAuthentication.Builder()
-                                .setType(UserAuthenticationType.password)
-                                .setPassword("p4ssw0rd")
+                .withSpec(new UserSpecBuilder()
+                        .withUsername("user3")
+                        .withAuthentication(new UserAuthenticationBuilder()
+                                .withType(UserAuthenticationType.password)
+                                .withPassword("p4ssw0rd")
                                 .build())
-                        .setAuthorization(Arrays.asList(
-                                new UserAuthorization.Builder()
-                                        .setAddresses(Arrays.asList("queue1", "topic1"))
-                                        .setOperations(Arrays.asList(Operation.send, Operation.recv))
+                        .withAuthorization(Arrays.asList(
+                                new UserAuthorizationBuilder()
+                                        .withAddresses(Arrays.asList("queue1", "topic1"))
+                                        .withOperations(Arrays.asList(Operation.send, Operation.recv))
                                         .build()))
                         .build())
                 .build();
@@ -235,21 +237,21 @@ public class HttpUserServiceTest {
     @Test
     public void testPutException() {
         userApi.throwException = true;
-        User u3 = new User.Builder()
-                .setMetadata(new UserMetadata.Builder()
-                        .setName("myspace.user1")
-                        .setNamespace("ns1")
+        User u3 = new UserBuilder()
+                .withMetadata(new ObjectMetaBuilder()
+                        .withName("myspace.user1")
+                        .withNamespace("ns1")
                         .build())
-                .setSpec(new UserSpec.Builder()
-                        .setUsername("user1")
-                        .setAuthentication(new UserAuthentication.Builder()
-                                .setType(UserAuthenticationType.password)
-                                .setPassword("p4ssw0rd")
+                .withSpec(new UserSpecBuilder()
+                        .withUsername("user1")
+                        .withAuthentication(new UserAuthenticationBuilder()
+                                .withType(UserAuthenticationType.password)
+                                .withPassword("p4ssw0rd")
                                 .build())
-                        .setAuthorization(Arrays.asList(
-                                new UserAuthorization.Builder()
-                                        .setAddresses(Arrays.asList("queue1", "topic1"))
-                                        .setOperations(Arrays.asList(Operation.send, Operation.recv))
+                        .withAuthorization(Arrays.asList(
+                                new UserAuthorizationBuilder()
+                                        .withAddresses(Arrays.asList("queue1", "topic1"))
+                                        .withOperations(Arrays.asList(Operation.send, Operation.recv))
                                         .build()))
                         .build())
                 .build();
@@ -259,21 +261,21 @@ public class HttpUserServiceTest {
 
     @Test
     public void testPutNotMatchingName() {
-        User u3 = new User.Builder()
-                .setMetadata(new UserMetadata.Builder()
-                        .setName("myspace.user3")
-                        .setNamespace("ns1")
+        User u3 = new UserBuilder()
+                .withMetadata(new ObjectMetaBuilder()
+                        .withName("myspace.user3")
+                        .withNamespace("ns1")
                         .build())
-                .setSpec(new UserSpec.Builder()
-                        .setUsername("user3")
-                        .setAuthentication(new UserAuthentication.Builder()
-                                .setType(UserAuthenticationType.password)
-                                .setPassword("p4ssw0rd")
+                .withSpec(new UserSpecBuilder()
+                        .withUsername("user3")
+                        .withAuthentication(new UserAuthenticationBuilder()
+                                .withType(UserAuthenticationType.password)
+                                .withPassword("p4ssw0rd")
                                 .build())
-                        .setAuthorization(Arrays.asList(
-                                new UserAuthorization.Builder()
-                                        .setAddresses(Arrays.asList("queue1", "topic1"))
-                                        .setOperations(Arrays.asList(Operation.send, Operation.recv))
+                        .withAuthorization(Arrays.asList(
+                                new UserAuthorizationBuilder()
+                                        .withAddresses(Arrays.asList("queue1", "topic1"))
+                                        .withOperations(Arrays.asList(Operation.send, Operation.recv))
                                         .build()))
                         .build())
                 .build();
@@ -283,21 +285,21 @@ public class HttpUserServiceTest {
 
     @Test
     public void testPutNotExists() {
-        User u3 = new User.Builder()
-                .setMetadata(new UserMetadata.Builder()
-                        .setName("myspace.user3")
-                        .setNamespace("ns1")
+        User u3 = new UserBuilder()
+                .withMetadata(new ObjectMetaBuilder()
+                        .withName("myspace.user3")
+                        .withNamespace("ns1")
                         .build())
-                .setSpec(new UserSpec.Builder()
-                        .setUsername("user3")
-                        .setAuthentication(new UserAuthentication.Builder()
-                                .setType(UserAuthenticationType.password)
-                                .setPassword("p4ssw0rd")
+                .withSpec(new UserSpecBuilder()
+                        .withUsername("user3")
+                        .withAuthentication(new UserAuthenticationBuilder()
+                                .withType(UserAuthenticationType.password)
+                                .withPassword("p4ssw0rd")
                                 .build())
-                        .setAuthorization(Arrays.asList(
-                                new UserAuthorization.Builder()
-                                        .setAddresses(Arrays.asList("queue1", "topic1"))
-                                        .setOperations(Arrays.asList(Operation.send, Operation.recv))
+                        .withAuthorization(Arrays.asList(
+                                new UserAuthorizationBuilder()
+                                        .withAddresses(Arrays.asList("queue1", "topic1"))
+                                        .withOperations(Arrays.asList(Operation.send, Operation.recv))
                                         .build()))
                         .build())
                 .build();
@@ -307,21 +309,21 @@ public class HttpUserServiceTest {
 
     @Test
     public void testPut() {
-        User u3 = new User.Builder()
-                .setMetadata(new UserMetadata.Builder()
-                        .setName("myspace.user1")
-                        .setNamespace("ns1")
+        User u3 = new UserBuilder()
+                .withMetadata(new ObjectMetaBuilder()
+                        .withName("myspace.user1")
+                        .withNamespace("ns1")
                         .build())
-                .setSpec(new UserSpec.Builder()
-                        .setUsername("user1")
-                        .setAuthentication(new UserAuthentication.Builder()
-                                .setType(UserAuthenticationType.password)
-                                .setPassword("p4ssw0rd")
+                .withSpec(new UserSpecBuilder()
+                        .withUsername("user1")
+                        .withAuthentication(new UserAuthenticationBuilder()
+                                .withType(UserAuthenticationType.password)
+                                .withPassword("p4ssw0rd")
                                 .build())
-                        .setAuthorization(Arrays.asList(
-                                new UserAuthorization.Builder()
-                                        .setAddresses(Arrays.asList("queue2", "topic2"))
-                                        .setOperations(Arrays.asList(Operation.send, Operation.recv))
+                        .withAuthorization(Arrays.asList(
+                                new UserAuthorizationBuilder()
+                                        .withAddresses(Arrays.asList("queue2", "topic2"))
+                                        .withOperations(Arrays.asList(Operation.send, Operation.recv))
                                         .build()))
                         .build())
                 .build();
diff --git a/api-server/src/test/java/io/enmasse/api/v1/http/TestUserApi.java b/api-server/src/test/java/io/enmasse/api/v1/http/TestUserApi.java
index 5824fab7a..617955ae2 100644
--- a/api-server/src/test/java/io/enmasse/api/v1/http/TestUserApi.java
+++ b/api-server/src/test/java/io/enmasse/api/v1/http/TestUserApi.java
@@ -75,7 +75,7 @@ public class TestUserApi implements UserApi  {
         for (Map<String, User> users : userMap.values()) {
             for (User user : users.values()) {
                 if (user.getMetadata().getNamespace().equals(namespace)) {
-                    list.add(user);
+                    list.getItems().add(user);
                 }
             }
         }
diff --git a/k8s-api/src/test/java/io/enmasse/k8s/api/AddressSpacePlanApiTest.java b/k8s-api/src/test/java/io/enmasse/k8s/api/AddressSpacePlanApiTest.java
index 0b34789f8..65c466674 100644
--- a/k8s-api/src/test/java/io/enmasse/k8s/api/AddressSpacePlanApiTest.java
+++ b/k8s-api/src/test/java/io/enmasse/k8s/api/AddressSpacePlanApiTest.java
@@ -32,7 +32,7 @@ public class AddressSpacePlanApiTest {
     @Test
     public void testNotifiesExisting() throws Exception {
         NamespacedOpenShiftClient client = openShiftServer.getOpenshiftClient();
-        CustomResourceDefinition crd = AdminCrd.addressspaceplans();
+        CustomResourceDefinition crd = AdminCrd.addressSpacePlans();
         AddressSpacePlanApi addressSpacePlanApi = new KubeAddressSpacePlanApi(client, client.getNamespace(), crd);
 
         client.customResources(crd, AddressSpacePlan.class, AddressSpacePlanList.class, DoneableAddressSpacePlan.class)
@@ -60,7 +60,7 @@ public class AddressSpacePlanApiTest {
     @Test
     public void testNotifiesCreated() throws Exception {
         NamespacedOpenShiftClient client = openShiftServer.getOpenshiftClient();
-        CustomResourceDefinition crd = AdminCrd.addressspaceplans();
+        CustomResourceDefinition crd = AdminCrd.addressSpacePlans();
         AddressSpacePlanApi addressSpacePlanApi = new KubeAddressSpacePlanApi(client, client.getNamespace(), crd);
 
         CompletableFuture<List<AddressSpacePlan>> promise = new CompletableFuture<>();
diff --git a/standard-controller/src/test/java/io/enmasse/controller/standard/StandardControllerSchema.java b/standard-controller/src/test/java/io/enmasse/controller/standard/StandardControllerSchema.java
index 76efdb0f9..899cab8ce 100644
--- a/standard-controller/src/test/java/io/enmasse/controller/standard/StandardControllerSchema.java
+++ b/standard-controller/src/test/java/io/enmasse/controller/standard/StandardControllerSchema.java
@@ -141,19 +141,32 @@ public class StandardControllerSchema implements SchemaProvider {
                                                         new ResourceRequest("broker", 0.1)))
                                                 .build()))
                                 .build()))
-                .setInfraConfigs(Arrays.asList(new StandardInfraConfig(new ObjectMetaBuilder()
-                        .withName("cfg1")
-                        .addToAnnotations(AnnotationKeys.QUEUE_TEMPLATE_NAME, "queuetemplate")
-                        .build(), new StandardInfraConfigSpec("latest", null,
-                        new StandardInfraConfigSpecAdmin(
-                                new StandardInfraConfigSpecAdminResources("512Mi")),
-                        new StandardInfraConfigSpecBroker(
-                                new StandardInfraConfigSpecBrokerResources("512Mi", "2Gi"),
-                                "FAIL", "default", false),
-                        new StandardInfraConfigSpecRouter(
-                                new StandardInfraConfigSpecRouterResources("512Mi"),
-                                1,
-                                500)))))
+                .setInfraConfigs(Arrays.asList(
+                        new StandardInfraConfigBuilder()
+                            .withMetadata(new ObjectMetaBuilder()
+                                    .withName("cfg1")
+                                    .addToAnnotations(AnnotationKeys.QUEUE_TEMPLATE_NAME, "queuetemplate")
+                                    .build()
+                                    )
+                            .withNewSpec()
+                                .withVersion("latest")
+                                .withNewAdmin()
+                                    .withNewResources("512Mi")
+                                    .endAdmin()
+                                .withNewBroker()
+                                    .withNewResources("512Mi", "2Gi")
+                                    .withAddressFullPolicy("FAIL")
+                                    .withStorageClassName("default")
+                                    .withUpdatePersistentVolumeClaim(false)
+                                    .endBroker()
+                                .withNewRouter()
+                                    .withNewResources("512Mi")
+                                    .withMinReplicas(1)
+                                    .withLinkCapacity(500)
+                                    .endRouter()
+                                .endSpec()
+                            .build()
+                        ))
                 .setInfraConfigDeserializer(json -> null)
                 .build();