func ValidateTraitObjectFn(_ context.Context, v ValidatingAppConfig) []error {
	klog.Info("validate applicationConfiguration", "name", v.appConfig.Name)
	var allErrs field.ErrorList
	for cidx, comp := range v.validatingComps {
		for idx, tr := range comp.validatingTraits {
			fldPath := field.NewPath("spec").Child("components").Index(cidx).Child("traits").Index(idx).Child("trait")
			content := tr.traitContent.Object
			if content[TraitTypeField] != nil {
				allErrs = append(allErrs, field.Invalid(fldPath, string(tr.componentTrait.Trait.Raw),
					"the trait contains 'name' info that should be mutated to GVK"))
			}
			if content[TraitSpecField] != nil {
				allErrs = append(allErrs, field.Invalid(fldPath, string(tr.componentTrait.Trait.Raw),
					"the trait contains 'properties' info that should be mutated to spec"))
			}
			if len(tr.traitContent.GetAPIVersion()) == 0 || len(tr.traitContent.GetKind()) == 0 {
				allErrs = append(allErrs, field.Invalid(fldPath, content,
					fmt.Sprintf("the trait data missing GVK, api = %s, kind = %s,",
						tr.traitContent.GetAPIVersion(), tr.traitContent.GetKind())))
			}
		}
	}
	if len(allErrs) > 0 {
		return allErrs.ToAggregate().Errors()
	}
	return nil
}
ValidateTraitObjectFn validates the ApplicationConfiguration on creation/update
package applicationconfiguration
import (
	"context"
	"fmt"
	"net/http"
	"strings"
	"github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2"
	"github.com/crossplane/oam-kubernetes-runtime/pkg/oam/discoverymapper"
	admissionv1beta1 "k8s.io/api/admission/v1beta1"
	"k8s.io/apimachinery/pkg/runtime/schema"
	utilerrors "k8s.io/apimachinery/pkg/util/errors"
	"k8s.io/apimachinery/pkg/util/validation/field"
	"k8s.io/klog"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/manager"
	"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
	"sigs.k8s.io/controller-runtime/pkg/webhook"
	"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)
const (
	errFmtWorkloadNameNotEmpty = "versioning-enabled component's workload name MUST NOT be assigned, expect workload name %q to be empty."
	errFmtRevisionName = "componentName %q and revisionName %q are mutually exclusive, you can only specify one of them"
	errFmtUnappliableTrait = "the trait %q cannot apply to workload %q of component %q (appliable: %q)"
	WorkloadNamePath = "metadata.name"
)
var appConfigResource = v1alpha2.SchemeGroupVersion.WithResource("applicationconfigurations")
type AppConfigValidator interface {
	Validate(context.Context, ValidatingAppConfig) []error
}
type AppConfigValidateFunc func(context.Context, ValidatingAppConfig) []error
func (fn AppConfigValidateFunc) Validate(ctx context.Context, v ValidatingAppConfig) []error {
	return fn(ctx, v)
}
type ValidatingHandler struct {
	Client client.Client
	Mapper discoverymapper.DiscoveryMapper
	Decoder *admission.Decoder
	Validators []AppConfigValidator
}
var _ admission.Handler = &ValidatingHandler{}
func (h *ValidatingHandler) Handle(ctx context.Context, req admission.Request) admission.Response {
	obj := &v1alpha2.ApplicationConfiguration{}
	if req.Resource.String() != appConfigResource.String() {
		return admission.Errored(http.StatusBadRequest, fmt.Errorf("expect resource to be %s", appConfigResource))
	}
	switch req.Operation {  
	case admissionv1beta1.Delete:
		if len(req.OldObject.Raw) != 0 {
			if err := h.Decoder.DecodeRaw(req.OldObject, obj); err != nil {
				return admission.Errored(http.StatusBadRequest, err)
			}
		} else {
			klog.Info("deleting Application Configuration", req.Name)
		}
	default:
		err := h.Decoder.Decode(req, obj)
		if err != nil {
			return admission.Errored(http.StatusBadRequest, err)
		}
		vAppConfig := &ValidatingAppConfig{}
		if err := vAppConfig.PrepareForValidation(ctx, h.Client, h.Mapper, obj); err != nil {
			klog.Info("failed init appConfig before validation ", " name: ", obj.Name, " errMsg: ", err.Error())
			return admission.Denied(err.Error())
		}
		for _, validator := range h.Validators {
			if allErrs := validator.Validate(ctx, *vAppConfig); utilerrors.NewAggregate(allErrs) != nil {
				klog.Info("validation failed ", " name: ", obj.Name, " errMsgi: ", utilerrors.NewAggregate(allErrs).Error())
				return admission.Denied(utilerrors.NewAggregate(allErrs).Error())
			}
		}
	}
	return admission.ValidationResponse(true, "")
}