deps: remove dependency of github.com/golang/protobuf from main module (#7122)

diff --git a/codegen.sh b/codegen.sh
deleted file mode 100755
index 4cdc6ba..0000000
--- a/codegen.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/usr/bin/env bash
-
-# This script serves as an example to demonstrate how to generate the gRPC-Go
-# interface and the related messages from .proto file.
-#
-# It assumes the installation of i) Google proto buffer compiler at
-# https://github.com/google/protobuf (after v2.6.1) and ii) the Go codegen
-# plugin at https://github.com/golang/protobuf (after 2015-02-20). If you have
-# not, please install them first.
-#
-# We recommend running this script at $GOPATH/src.
-#
-# If this is not what you need, feel free to make your own scripts. Again, this
-# script is for demonstration purpose.
-#
-proto=$1
-protoc --go_out=plugins=grpc:. $proto
diff --git a/examples/gotutorial.md b/examples/gotutorial.md
index 8699356..2f209fa 100644
--- a/examples/gotutorial.md
+++ b/examples/gotutorial.md
@@ -89,18 +89,10 @@
 
 ## Generating client and server code
 
-Next we need to generate the gRPC client and server interfaces from our `.proto` service definition. We do this using the protocol buffer compiler `protoc` with a special gRPC Go plugin.
-
-For simplicity, we've provided a [bash script](https://github.com/grpc/grpc-go/blob/master/codegen.sh) that runs `protoc` for you with the appropriate plugin, input, and output (if you want to run this by yourself, make sure you've installed protoc and followed the gRPC-Go [installation instructions](https://github.com/grpc/grpc-go/blob/master/README.md) first):
+Next we need to generate the gRPC client and server interfaces from our `.proto` service definition. We do this using the protocol buffer compiler `protoc` with a special gRPC Go plugin (if you want to run this by yourself, make sure you've installed protoc and followed the gRPC-Go [installation instructions](https://github.com/grpc/grpc-go/blob/master/README.md) first) and run:
 
 ```shell
-$ codegen.sh route_guide.proto
-```
-
-which actually runs:
-
-```shell
-$ protoc --go_out=plugins=grpc:. route_guide.proto
+protoc --go_out=.  --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative "route_guide.proto"
 ```
 
 Running this command generates the following file in your current directory:
diff --git a/go.mod b/go.mod
index 3184a45..f0b9275 100644
--- a/go.mod
+++ b/go.mod
@@ -7,7 +7,6 @@
 	github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50
 	github.com/envoyproxy/go-control-plane v0.12.0
 	github.com/golang/glog v1.2.0
-	github.com/golang/protobuf v1.5.4
 	github.com/google/go-cmp v0.6.0
 	github.com/google/uuid v1.6.0
 	golang.org/x/net v0.22.0
@@ -23,6 +22,7 @@
 	cloud.google.com/go/compute/metadata v0.2.3 // indirect
 	github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect
 	github.com/envoyproxy/protoc-gen-validate v1.0.4 // indirect
+	github.com/golang/protobuf v1.5.4 // indirect
 	golang.org/x/text v0.14.0 // indirect
 	google.golang.org/appengine v1.6.8 // indirect
 	google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 // indirect
diff --git a/reflection/adapt.go b/reflection/adapt.go
index 33b907a..6997e47 100644
--- a/reflection/adapt.go
+++ b/reflection/adapt.go
@@ -19,10 +19,11 @@
 package reflection
 
 import (
+	"google.golang.org/grpc/reflection/internal"
+
 	v1reflectiongrpc "google.golang.org/grpc/reflection/grpc_reflection_v1"
 	v1reflectionpb "google.golang.org/grpc/reflection/grpc_reflection_v1"
 	v1alphareflectiongrpc "google.golang.org/grpc/reflection/grpc_reflection_v1alpha"
-	v1alphareflectionpb "google.golang.org/grpc/reflection/grpc_reflection_v1alpha"
 )
 
 // asV1Alpha returns an implementation of the v1alpha version of the reflection
@@ -44,7 +45,7 @@
 }
 
 func (s v1AlphaServerStreamAdapter) Send(response *v1reflectionpb.ServerReflectionResponse) error {
-	return s.ServerReflection_ServerReflectionInfoServer.Send(v1ToV1AlphaResponse(response))
+	return s.ServerReflection_ServerReflectionInfoServer.Send(internal.V1ToV1AlphaResponse(response))
 }
 
 func (s v1AlphaServerStreamAdapter) Recv() (*v1reflectionpb.ServerReflectionRequest, error) {
@@ -52,136 +53,5 @@
 	if err != nil {
 		return nil, err
 	}
-	return v1AlphaToV1Request(resp), nil
-}
-
-func v1ToV1AlphaResponse(v1 *v1reflectionpb.ServerReflectionResponse) *v1alphareflectionpb.ServerReflectionResponse {
-	var v1alpha v1alphareflectionpb.ServerReflectionResponse
-	v1alpha.ValidHost = v1.ValidHost
-	if v1.OriginalRequest != nil {
-		v1alpha.OriginalRequest = v1ToV1AlphaRequest(v1.OriginalRequest)
-	}
-	switch mr := v1.MessageResponse.(type) {
-	case *v1reflectionpb.ServerReflectionResponse_FileDescriptorResponse:
-		if mr != nil {
-			v1alpha.MessageResponse = &v1alphareflectionpb.ServerReflectionResponse_FileDescriptorResponse{
-				FileDescriptorResponse: &v1alphareflectionpb.FileDescriptorResponse{
-					FileDescriptorProto: mr.FileDescriptorResponse.GetFileDescriptorProto(),
-				},
-			}
-		}
-	case *v1reflectionpb.ServerReflectionResponse_AllExtensionNumbersResponse:
-		if mr != nil {
-			v1alpha.MessageResponse = &v1alphareflectionpb.ServerReflectionResponse_AllExtensionNumbersResponse{
-				AllExtensionNumbersResponse: &v1alphareflectionpb.ExtensionNumberResponse{
-					BaseTypeName:    mr.AllExtensionNumbersResponse.GetBaseTypeName(),
-					ExtensionNumber: mr.AllExtensionNumbersResponse.GetExtensionNumber(),
-				},
-			}
-		}
-	case *v1reflectionpb.ServerReflectionResponse_ListServicesResponse:
-		if mr != nil {
-			svcs := make([]*v1alphareflectionpb.ServiceResponse, len(mr.ListServicesResponse.GetService()))
-			for i, svc := range mr.ListServicesResponse.GetService() {
-				svcs[i] = &v1alphareflectionpb.ServiceResponse{
-					Name: svc.GetName(),
-				}
-			}
-			v1alpha.MessageResponse = &v1alphareflectionpb.ServerReflectionResponse_ListServicesResponse{
-				ListServicesResponse: &v1alphareflectionpb.ListServiceResponse{
-					Service: svcs,
-				},
-			}
-		}
-	case *v1reflectionpb.ServerReflectionResponse_ErrorResponse:
-		if mr != nil {
-			v1alpha.MessageResponse = &v1alphareflectionpb.ServerReflectionResponse_ErrorResponse{
-				ErrorResponse: &v1alphareflectionpb.ErrorResponse{
-					ErrorCode:    mr.ErrorResponse.GetErrorCode(),
-					ErrorMessage: mr.ErrorResponse.GetErrorMessage(),
-				},
-			}
-		}
-	default:
-		// no value set
-	}
-	return &v1alpha
-}
-
-func v1AlphaToV1Request(v1alpha *v1alphareflectionpb.ServerReflectionRequest) *v1reflectionpb.ServerReflectionRequest {
-	var v1 v1reflectionpb.ServerReflectionRequest
-	v1.Host = v1alpha.Host
-	switch mr := v1alpha.MessageRequest.(type) {
-	case *v1alphareflectionpb.ServerReflectionRequest_FileByFilename:
-		v1.MessageRequest = &v1reflectionpb.ServerReflectionRequest_FileByFilename{
-			FileByFilename: mr.FileByFilename,
-		}
-	case *v1alphareflectionpb.ServerReflectionRequest_FileContainingSymbol:
-		v1.MessageRequest = &v1reflectionpb.ServerReflectionRequest_FileContainingSymbol{
-			FileContainingSymbol: mr.FileContainingSymbol,
-		}
-	case *v1alphareflectionpb.ServerReflectionRequest_FileContainingExtension:
-		if mr.FileContainingExtension != nil {
-			v1.MessageRequest = &v1reflectionpb.ServerReflectionRequest_FileContainingExtension{
-				FileContainingExtension: &v1reflectionpb.ExtensionRequest{
-					ContainingType:  mr.FileContainingExtension.GetContainingType(),
-					ExtensionNumber: mr.FileContainingExtension.GetExtensionNumber(),
-				},
-			}
-		}
-	case *v1alphareflectionpb.ServerReflectionRequest_AllExtensionNumbersOfType:
-		v1.MessageRequest = &v1reflectionpb.ServerReflectionRequest_AllExtensionNumbersOfType{
-			AllExtensionNumbersOfType: mr.AllExtensionNumbersOfType,
-		}
-	case *v1alphareflectionpb.ServerReflectionRequest_ListServices:
-		v1.MessageRequest = &v1reflectionpb.ServerReflectionRequest_ListServices{
-			ListServices: mr.ListServices,
-		}
-	default:
-		// no value set
-	}
-	return &v1
-}
-
-func v1ToV1AlphaRequest(v1 *v1reflectionpb.ServerReflectionRequest) *v1alphareflectionpb.ServerReflectionRequest {
-	var v1alpha v1alphareflectionpb.ServerReflectionRequest
-	v1alpha.Host = v1.Host
-	switch mr := v1.MessageRequest.(type) {
-	case *v1reflectionpb.ServerReflectionRequest_FileByFilename:
-		if mr != nil {
-			v1alpha.MessageRequest = &v1alphareflectionpb.ServerReflectionRequest_FileByFilename{
-				FileByFilename: mr.FileByFilename,
-			}
-		}
-	case *v1reflectionpb.ServerReflectionRequest_FileContainingSymbol:
-		if mr != nil {
-			v1alpha.MessageRequest = &v1alphareflectionpb.ServerReflectionRequest_FileContainingSymbol{
-				FileContainingSymbol: mr.FileContainingSymbol,
-			}
-		}
-	case *v1reflectionpb.ServerReflectionRequest_FileContainingExtension:
-		if mr != nil {
-			v1alpha.MessageRequest = &v1alphareflectionpb.ServerReflectionRequest_FileContainingExtension{
-				FileContainingExtension: &v1alphareflectionpb.ExtensionRequest{
-					ContainingType:  mr.FileContainingExtension.GetContainingType(),
-					ExtensionNumber: mr.FileContainingExtension.GetExtensionNumber(),
-				},
-			}
-		}
-	case *v1reflectionpb.ServerReflectionRequest_AllExtensionNumbersOfType:
-		if mr != nil {
-			v1alpha.MessageRequest = &v1alphareflectionpb.ServerReflectionRequest_AllExtensionNumbersOfType{
-				AllExtensionNumbersOfType: mr.AllExtensionNumbersOfType,
-			}
-		}
-	case *v1reflectionpb.ServerReflectionRequest_ListServices:
-		if mr != nil {
-			v1alpha.MessageRequest = &v1alphareflectionpb.ServerReflectionRequest_ListServices{
-				ListServices: mr.ListServices,
-			}
-		}
-	default:
-		// no value set
-	}
-	return &v1alpha
+	return internal.V1AlphaToV1Request(resp), nil
 }
diff --git a/reflection/internal/internal.go b/reflection/internal/internal.go
new file mode 100644
index 0000000..36ee650
--- /dev/null
+++ b/reflection/internal/internal.go
@@ -0,0 +1,436 @@
+/*
+ *
+ * Copyright 2024 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// Package internal contains code that is shared by both reflection package and
+// the test package. The packages are split in this way inorder to avoid
+// depenedency to deprecated package github.com/golang/protobuf.
+package internal
+
+import (
+	"io"
+	"sort"
+
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/status"
+	"google.golang.org/protobuf/proto"
+	"google.golang.org/protobuf/reflect/protodesc"
+	"google.golang.org/protobuf/reflect/protoreflect"
+	"google.golang.org/protobuf/reflect/protoregistry"
+
+	v1reflectiongrpc "google.golang.org/grpc/reflection/grpc_reflection_v1"
+	v1reflectionpb "google.golang.org/grpc/reflection/grpc_reflection_v1"
+	v1alphareflectiongrpc "google.golang.org/grpc/reflection/grpc_reflection_v1alpha"
+	v1alphareflectionpb "google.golang.org/grpc/reflection/grpc_reflection_v1alpha"
+)
+
+// ServiceInfoProvider is an interface used to retrieve metadata about the
+// services to expose.
+type ServiceInfoProvider interface {
+	GetServiceInfo() map[string]grpc.ServiceInfo
+}
+
+// ExtensionResolver is the interface used to query details about extensions.
+// This interface is satisfied by protoregistry.GlobalTypes.
+type ExtensionResolver interface {
+	protoregistry.ExtensionTypeResolver
+	RangeExtensionsByMessage(message protoreflect.FullName, f func(protoreflect.ExtensionType) bool)
+}
+
+// ServerReflectionServer is the server API for ServerReflection service.
+type ServerReflectionServer struct {
+	v1alphareflectiongrpc.UnimplementedServerReflectionServer
+	S            ServiceInfoProvider
+	DescResolver protodesc.Resolver
+	ExtResolver  ExtensionResolver
+}
+
+// FileDescWithDependencies returns a slice of serialized fileDescriptors in
+// wire format ([]byte). The fileDescriptors will include fd and all the
+// transitive dependencies of fd with names not in sentFileDescriptors.
+func (s *ServerReflectionServer) FileDescWithDependencies(fd protoreflect.FileDescriptor, sentFileDescriptors map[string]bool) ([][]byte, error) {
+	if fd.IsPlaceholder() {
+		// If the given root file is a placeholder, treat it
+		// as missing instead of serializing it.
+		return nil, protoregistry.NotFound
+	}
+	var r [][]byte
+	queue := []protoreflect.FileDescriptor{fd}
+	for len(queue) > 0 {
+		currentfd := queue[0]
+		queue = queue[1:]
+		if currentfd.IsPlaceholder() {
+			// Skip any missing files in the dependency graph.
+			continue
+		}
+		if sent := sentFileDescriptors[currentfd.Path()]; len(r) == 0 || !sent {
+			sentFileDescriptors[currentfd.Path()] = true
+			fdProto := protodesc.ToFileDescriptorProto(currentfd)
+			currentfdEncoded, err := proto.Marshal(fdProto)
+			if err != nil {
+				return nil, err
+			}
+			r = append(r, currentfdEncoded)
+		}
+		for i := 0; i < currentfd.Imports().Len(); i++ {
+			queue = append(queue, currentfd.Imports().Get(i))
+		}
+	}
+	return r, nil
+}
+
+// FileDescEncodingContainingSymbol finds the file descriptor containing the
+// given symbol, finds all of its previously unsent transitive dependencies,
+// does marshalling on them, and returns the marshalled result. The given symbol
+// can be a type, a service or a method.
+func (s *ServerReflectionServer) FileDescEncodingContainingSymbol(name string, sentFileDescriptors map[string]bool) ([][]byte, error) {
+	d, err := s.DescResolver.FindDescriptorByName(protoreflect.FullName(name))
+	if err != nil {
+		return nil, err
+	}
+	return s.FileDescWithDependencies(d.ParentFile(), sentFileDescriptors)
+}
+
+// FileDescEncodingContainingExtension finds the file descriptor containing
+// given extension, finds all of its previously unsent transitive dependencies,
+// does marshalling on them, and returns the marshalled result.
+func (s *ServerReflectionServer) FileDescEncodingContainingExtension(typeName string, extNum int32, sentFileDescriptors map[string]bool) ([][]byte, error) {
+	xt, err := s.ExtResolver.FindExtensionByNumber(protoreflect.FullName(typeName), protoreflect.FieldNumber(extNum))
+	if err != nil {
+		return nil, err
+	}
+	return s.FileDescWithDependencies(xt.TypeDescriptor().ParentFile(), sentFileDescriptors)
+}
+
+// AllExtensionNumbersForTypeName returns all extension numbers for the given type.
+func (s *ServerReflectionServer) AllExtensionNumbersForTypeName(name string) ([]int32, error) {
+	var numbers []int32
+	s.ExtResolver.RangeExtensionsByMessage(protoreflect.FullName(name), func(xt protoreflect.ExtensionType) bool {
+		numbers = append(numbers, int32(xt.TypeDescriptor().Number()))
+		return true
+	})
+	sort.Slice(numbers, func(i, j int) bool {
+		return numbers[i] < numbers[j]
+	})
+	if len(numbers) == 0 {
+		// maybe return an error if given type name is not known
+		if _, err := s.DescResolver.FindDescriptorByName(protoreflect.FullName(name)); err != nil {
+			return nil, err
+		}
+	}
+	return numbers, nil
+}
+
+// ListServices returns the names of services this server exposes.
+func (s *ServerReflectionServer) ListServices() []*v1reflectionpb.ServiceResponse {
+	serviceInfo := s.S.GetServiceInfo()
+	resp := make([]*v1reflectionpb.ServiceResponse, 0, len(serviceInfo))
+	for svc := range serviceInfo {
+		resp = append(resp, &v1reflectionpb.ServiceResponse{Name: svc})
+	}
+	sort.Slice(resp, func(i, j int) bool {
+		return resp[i].Name < resp[j].Name
+	})
+	return resp
+}
+
+// ServerReflectionInfo is the reflection service handler.
+func (s *ServerReflectionServer) ServerReflectionInfo(stream v1reflectiongrpc.ServerReflection_ServerReflectionInfoServer) error {
+	sentFileDescriptors := make(map[string]bool)
+	for {
+		in, err := stream.Recv()
+		if err == io.EOF {
+			return nil
+		}
+		if err != nil {
+			return err
+		}
+
+		out := &v1reflectionpb.ServerReflectionResponse{
+			ValidHost:       in.Host,
+			OriginalRequest: in,
+		}
+		switch req := in.MessageRequest.(type) {
+		case *v1reflectionpb.ServerReflectionRequest_FileByFilename:
+			var b [][]byte
+			fd, err := s.DescResolver.FindFileByPath(req.FileByFilename)
+			if err == nil {
+				b, err = s.FileDescWithDependencies(fd, sentFileDescriptors)
+			}
+			if err != nil {
+				out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_ErrorResponse{
+					ErrorResponse: &v1reflectionpb.ErrorResponse{
+						ErrorCode:    int32(codes.NotFound),
+						ErrorMessage: err.Error(),
+					},
+				}
+			} else {
+				out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_FileDescriptorResponse{
+					FileDescriptorResponse: &v1reflectionpb.FileDescriptorResponse{FileDescriptorProto: b},
+				}
+			}
+		case *v1reflectionpb.ServerReflectionRequest_FileContainingSymbol:
+			b, err := s.FileDescEncodingContainingSymbol(req.FileContainingSymbol, sentFileDescriptors)
+			if err != nil {
+				out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_ErrorResponse{
+					ErrorResponse: &v1reflectionpb.ErrorResponse{
+						ErrorCode:    int32(codes.NotFound),
+						ErrorMessage: err.Error(),
+					},
+				}
+			} else {
+				out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_FileDescriptorResponse{
+					FileDescriptorResponse: &v1reflectionpb.FileDescriptorResponse{FileDescriptorProto: b},
+				}
+			}
+		case *v1reflectionpb.ServerReflectionRequest_FileContainingExtension:
+			typeName := req.FileContainingExtension.ContainingType
+			extNum := req.FileContainingExtension.ExtensionNumber
+			b, err := s.FileDescEncodingContainingExtension(typeName, extNum, sentFileDescriptors)
+			if err != nil {
+				out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_ErrorResponse{
+					ErrorResponse: &v1reflectionpb.ErrorResponse{
+						ErrorCode:    int32(codes.NotFound),
+						ErrorMessage: err.Error(),
+					},
+				}
+			} else {
+				out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_FileDescriptorResponse{
+					FileDescriptorResponse: &v1reflectionpb.FileDescriptorResponse{FileDescriptorProto: b},
+				}
+			}
+		case *v1reflectionpb.ServerReflectionRequest_AllExtensionNumbersOfType:
+			extNums, err := s.AllExtensionNumbersForTypeName(req.AllExtensionNumbersOfType)
+			if err != nil {
+				out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_ErrorResponse{
+					ErrorResponse: &v1reflectionpb.ErrorResponse{
+						ErrorCode:    int32(codes.NotFound),
+						ErrorMessage: err.Error(),
+					},
+				}
+			} else {
+				out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_AllExtensionNumbersResponse{
+					AllExtensionNumbersResponse: &v1reflectionpb.ExtensionNumberResponse{
+						BaseTypeName:    req.AllExtensionNumbersOfType,
+						ExtensionNumber: extNums,
+					},
+				}
+			}
+		case *v1reflectionpb.ServerReflectionRequest_ListServices:
+			out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_ListServicesResponse{
+				ListServicesResponse: &v1reflectionpb.ListServiceResponse{
+					Service: s.ListServices(),
+				},
+			}
+		default:
+			return status.Errorf(codes.InvalidArgument, "invalid MessageRequest: %v", in.MessageRequest)
+		}
+
+		if err := stream.Send(out); err != nil {
+			return err
+		}
+	}
+}
+
+// V1ToV1AlphaResponse converts a v1 ServerReflectionResponse to a v1alpha.
+func V1ToV1AlphaResponse(v1 *v1reflectionpb.ServerReflectionResponse) *v1alphareflectionpb.ServerReflectionResponse {
+	var v1alpha v1alphareflectionpb.ServerReflectionResponse
+	v1alpha.ValidHost = v1.ValidHost
+	if v1.OriginalRequest != nil {
+		v1alpha.OriginalRequest = V1ToV1AlphaRequest(v1.OriginalRequest)
+	}
+	switch mr := v1.MessageResponse.(type) {
+	case *v1reflectionpb.ServerReflectionResponse_FileDescriptorResponse:
+		if mr != nil {
+			v1alpha.MessageResponse = &v1alphareflectionpb.ServerReflectionResponse_FileDescriptorResponse{
+				FileDescriptorResponse: &v1alphareflectionpb.FileDescriptorResponse{
+					FileDescriptorProto: mr.FileDescriptorResponse.GetFileDescriptorProto(),
+				},
+			}
+		}
+	case *v1reflectionpb.ServerReflectionResponse_AllExtensionNumbersResponse:
+		if mr != nil {
+			v1alpha.MessageResponse = &v1alphareflectionpb.ServerReflectionResponse_AllExtensionNumbersResponse{
+				AllExtensionNumbersResponse: &v1alphareflectionpb.ExtensionNumberResponse{
+					BaseTypeName:    mr.AllExtensionNumbersResponse.GetBaseTypeName(),
+					ExtensionNumber: mr.AllExtensionNumbersResponse.GetExtensionNumber(),
+				},
+			}
+		}
+	case *v1reflectionpb.ServerReflectionResponse_ListServicesResponse:
+		if mr != nil {
+			svcs := make([]*v1alphareflectionpb.ServiceResponse, len(mr.ListServicesResponse.GetService()))
+			for i, svc := range mr.ListServicesResponse.GetService() {
+				svcs[i] = &v1alphareflectionpb.ServiceResponse{
+					Name: svc.GetName(),
+				}
+			}
+			v1alpha.MessageResponse = &v1alphareflectionpb.ServerReflectionResponse_ListServicesResponse{
+				ListServicesResponse: &v1alphareflectionpb.ListServiceResponse{
+					Service: svcs,
+				},
+			}
+		}
+	case *v1reflectionpb.ServerReflectionResponse_ErrorResponse:
+		if mr != nil {
+			v1alpha.MessageResponse = &v1alphareflectionpb.ServerReflectionResponse_ErrorResponse{
+				ErrorResponse: &v1alphareflectionpb.ErrorResponse{
+					ErrorCode:    mr.ErrorResponse.GetErrorCode(),
+					ErrorMessage: mr.ErrorResponse.GetErrorMessage(),
+				},
+			}
+		}
+	default:
+		// no value set
+	}
+	return &v1alpha
+}
+
+// V1AlphaToV1Request converts a v1alpha ServerReflectionRequest to a v1.
+func V1AlphaToV1Request(v1alpha *v1alphareflectionpb.ServerReflectionRequest) *v1reflectionpb.ServerReflectionRequest {
+	var v1 v1reflectionpb.ServerReflectionRequest
+	v1.Host = v1alpha.Host
+	switch mr := v1alpha.MessageRequest.(type) {
+	case *v1alphareflectionpb.ServerReflectionRequest_FileByFilename:
+		v1.MessageRequest = &v1reflectionpb.ServerReflectionRequest_FileByFilename{
+			FileByFilename: mr.FileByFilename,
+		}
+	case *v1alphareflectionpb.ServerReflectionRequest_FileContainingSymbol:
+		v1.MessageRequest = &v1reflectionpb.ServerReflectionRequest_FileContainingSymbol{
+			FileContainingSymbol: mr.FileContainingSymbol,
+		}
+	case *v1alphareflectionpb.ServerReflectionRequest_FileContainingExtension:
+		if mr.FileContainingExtension != nil {
+			v1.MessageRequest = &v1reflectionpb.ServerReflectionRequest_FileContainingExtension{
+				FileContainingExtension: &v1reflectionpb.ExtensionRequest{
+					ContainingType:  mr.FileContainingExtension.GetContainingType(),
+					ExtensionNumber: mr.FileContainingExtension.GetExtensionNumber(),
+				},
+			}
+		}
+	case *v1alphareflectionpb.ServerReflectionRequest_AllExtensionNumbersOfType:
+		v1.MessageRequest = &v1reflectionpb.ServerReflectionRequest_AllExtensionNumbersOfType{
+			AllExtensionNumbersOfType: mr.AllExtensionNumbersOfType,
+		}
+	case *v1alphareflectionpb.ServerReflectionRequest_ListServices:
+		v1.MessageRequest = &v1reflectionpb.ServerReflectionRequest_ListServices{
+			ListServices: mr.ListServices,
+		}
+	default:
+		// no value set
+	}
+	return &v1
+}
+
+// V1ToV1AlphaRequest converts a v1 ServerReflectionRequest to a v1alpha.
+func V1ToV1AlphaRequest(v1 *v1reflectionpb.ServerReflectionRequest) *v1alphareflectionpb.ServerReflectionRequest {
+	var v1alpha v1alphareflectionpb.ServerReflectionRequest
+	v1alpha.Host = v1.Host
+	switch mr := v1.MessageRequest.(type) {
+	case *v1reflectionpb.ServerReflectionRequest_FileByFilename:
+		if mr != nil {
+			v1alpha.MessageRequest = &v1alphareflectionpb.ServerReflectionRequest_FileByFilename{
+				FileByFilename: mr.FileByFilename,
+			}
+		}
+	case *v1reflectionpb.ServerReflectionRequest_FileContainingSymbol:
+		if mr != nil {
+			v1alpha.MessageRequest = &v1alphareflectionpb.ServerReflectionRequest_FileContainingSymbol{
+				FileContainingSymbol: mr.FileContainingSymbol,
+			}
+		}
+	case *v1reflectionpb.ServerReflectionRequest_FileContainingExtension:
+		if mr != nil {
+			v1alpha.MessageRequest = &v1alphareflectionpb.ServerReflectionRequest_FileContainingExtension{
+				FileContainingExtension: &v1alphareflectionpb.ExtensionRequest{
+					ContainingType:  mr.FileContainingExtension.GetContainingType(),
+					ExtensionNumber: mr.FileContainingExtension.GetExtensionNumber(),
+				},
+			}
+		}
+	case *v1reflectionpb.ServerReflectionRequest_AllExtensionNumbersOfType:
+		if mr != nil {
+			v1alpha.MessageRequest = &v1alphareflectionpb.ServerReflectionRequest_AllExtensionNumbersOfType{
+				AllExtensionNumbersOfType: mr.AllExtensionNumbersOfType,
+			}
+		}
+	case *v1reflectionpb.ServerReflectionRequest_ListServices:
+		if mr != nil {
+			v1alpha.MessageRequest = &v1alphareflectionpb.ServerReflectionRequest_ListServices{
+				ListServices: mr.ListServices,
+			}
+		}
+	default:
+		// no value set
+	}
+	return &v1alpha
+}
+
+// V1AlphaToV1Response converts a v1alpha ServerReflectionResponse to a v1.
+func V1AlphaToV1Response(v1alpha *v1alphareflectionpb.ServerReflectionResponse) *v1reflectionpb.ServerReflectionResponse {
+	var v1 v1reflectionpb.ServerReflectionResponse
+	v1.ValidHost = v1alpha.ValidHost
+	if v1alpha.OriginalRequest != nil {
+		v1.OriginalRequest = V1AlphaToV1Request(v1alpha.OriginalRequest)
+	}
+	switch mr := v1alpha.MessageResponse.(type) {
+	case *v1alphareflectionpb.ServerReflectionResponse_FileDescriptorResponse:
+		if mr != nil {
+			v1.MessageResponse = &v1reflectionpb.ServerReflectionResponse_FileDescriptorResponse{
+				FileDescriptorResponse: &v1reflectionpb.FileDescriptorResponse{
+					FileDescriptorProto: mr.FileDescriptorResponse.GetFileDescriptorProto(),
+				},
+			}
+		}
+	case *v1alphareflectionpb.ServerReflectionResponse_AllExtensionNumbersResponse:
+		if mr != nil {
+			v1.MessageResponse = &v1reflectionpb.ServerReflectionResponse_AllExtensionNumbersResponse{
+				AllExtensionNumbersResponse: &v1reflectionpb.ExtensionNumberResponse{
+					BaseTypeName:    mr.AllExtensionNumbersResponse.GetBaseTypeName(),
+					ExtensionNumber: mr.AllExtensionNumbersResponse.GetExtensionNumber(),
+				},
+			}
+		}
+	case *v1alphareflectionpb.ServerReflectionResponse_ListServicesResponse:
+		if mr != nil {
+			svcs := make([]*v1reflectionpb.ServiceResponse, len(mr.ListServicesResponse.GetService()))
+			for i, svc := range mr.ListServicesResponse.GetService() {
+				svcs[i] = &v1reflectionpb.ServiceResponse{
+					Name: svc.GetName(),
+				}
+			}
+			v1.MessageResponse = &v1reflectionpb.ServerReflectionResponse_ListServicesResponse{
+				ListServicesResponse: &v1reflectionpb.ListServiceResponse{
+					Service: svcs,
+				},
+			}
+		}
+	case *v1alphareflectionpb.ServerReflectionResponse_ErrorResponse:
+		if mr != nil {
+			v1.MessageResponse = &v1reflectionpb.ServerReflectionResponse_ErrorResponse{
+				ErrorResponse: &v1reflectionpb.ErrorResponse{
+					ErrorCode:    mr.ErrorResponse.GetErrorCode(),
+					ErrorMessage: mr.ErrorResponse.GetErrorMessage(),
+				},
+			}
+		}
+	default:
+		// no value set
+	}
+	return &v1
+}
diff --git a/reflection/serverreflection.go b/reflection/serverreflection.go
index c3b4083..13a94e2 100644
--- a/reflection/serverreflection.go
+++ b/reflection/serverreflection.go
@@ -37,19 +37,13 @@
 package reflection // import "google.golang.org/grpc/reflection"
 
 import (
-	"io"
-	"sort"
-
 	"google.golang.org/grpc"
-	"google.golang.org/grpc/codes"
-	"google.golang.org/grpc/status"
-	"google.golang.org/protobuf/proto"
+	"google.golang.org/grpc/reflection/internal"
 	"google.golang.org/protobuf/reflect/protodesc"
 	"google.golang.org/protobuf/reflect/protoreflect"
 	"google.golang.org/protobuf/reflect/protoregistry"
 
 	v1reflectiongrpc "google.golang.org/grpc/reflection/grpc_reflection_v1"
-	v1reflectionpb "google.golang.org/grpc/reflection/grpc_reflection_v1"
 	v1alphareflectiongrpc "google.golang.org/grpc/reflection/grpc_reflection_v1alpha"
 )
 
@@ -158,203 +152,9 @@
 	if opts.ExtensionResolver == nil {
 		opts.ExtensionResolver = protoregistry.GlobalTypes
 	}
-	return &serverReflectionServer{
-		s:            opts.Services,
-		descResolver: opts.DescriptorResolver,
-		extResolver:  opts.ExtensionResolver,
-	}
-}
-
-type serverReflectionServer struct {
-	v1alphareflectiongrpc.UnimplementedServerReflectionServer
-	s            ServiceInfoProvider
-	descResolver protodesc.Resolver
-	extResolver  ExtensionResolver
-}
-
-// fileDescWithDependencies returns a slice of serialized fileDescriptors in
-// wire format ([]byte). The fileDescriptors will include fd and all the
-// transitive dependencies of fd with names not in sentFileDescriptors.
-func (s *serverReflectionServer) fileDescWithDependencies(fd protoreflect.FileDescriptor, sentFileDescriptors map[string]bool) ([][]byte, error) {
-	if fd.IsPlaceholder() {
-		// If the given root file is a placeholder, treat it
-		// as missing instead of serializing it.
-		return nil, protoregistry.NotFound
-	}
-	var r [][]byte
-	queue := []protoreflect.FileDescriptor{fd}
-	for len(queue) > 0 {
-		currentfd := queue[0]
-		queue = queue[1:]
-		if currentfd.IsPlaceholder() {
-			// Skip any missing files in the dependency graph.
-			continue
-		}
-		if sent := sentFileDescriptors[currentfd.Path()]; len(r) == 0 || !sent {
-			sentFileDescriptors[currentfd.Path()] = true
-			fdProto := protodesc.ToFileDescriptorProto(currentfd)
-			currentfdEncoded, err := proto.Marshal(fdProto)
-			if err != nil {
-				return nil, err
-			}
-			r = append(r, currentfdEncoded)
-		}
-		for i := 0; i < currentfd.Imports().Len(); i++ {
-			queue = append(queue, currentfd.Imports().Get(i))
-		}
-	}
-	return r, nil
-}
-
-// fileDescEncodingContainingSymbol finds the file descriptor containing the
-// given symbol, finds all of its previously unsent transitive dependencies,
-// does marshalling on them, and returns the marshalled result. The given symbol
-// can be a type, a service or a method.
-func (s *serverReflectionServer) fileDescEncodingContainingSymbol(name string, sentFileDescriptors map[string]bool) ([][]byte, error) {
-	d, err := s.descResolver.FindDescriptorByName(protoreflect.FullName(name))
-	if err != nil {
-		return nil, err
-	}
-	return s.fileDescWithDependencies(d.ParentFile(), sentFileDescriptors)
-}
-
-// fileDescEncodingContainingExtension finds the file descriptor containing
-// given extension, finds all of its previously unsent transitive dependencies,
-// does marshalling on them, and returns the marshalled result.
-func (s *serverReflectionServer) fileDescEncodingContainingExtension(typeName string, extNum int32, sentFileDescriptors map[string]bool) ([][]byte, error) {
-	xt, err := s.extResolver.FindExtensionByNumber(protoreflect.FullName(typeName), protoreflect.FieldNumber(extNum))
-	if err != nil {
-		return nil, err
-	}
-	return s.fileDescWithDependencies(xt.TypeDescriptor().ParentFile(), sentFileDescriptors)
-}
-
-// allExtensionNumbersForTypeName returns all extension numbers for the given type.
-func (s *serverReflectionServer) allExtensionNumbersForTypeName(name string) ([]int32, error) {
-	var numbers []int32
-	s.extResolver.RangeExtensionsByMessage(protoreflect.FullName(name), func(xt protoreflect.ExtensionType) bool {
-		numbers = append(numbers, int32(xt.TypeDescriptor().Number()))
-		return true
-	})
-	sort.Slice(numbers, func(i, j int) bool {
-		return numbers[i] < numbers[j]
-	})
-	if len(numbers) == 0 {
-		// maybe return an error if given type name is not known
-		if _, err := s.descResolver.FindDescriptorByName(protoreflect.FullName(name)); err != nil {
-			return nil, err
-		}
-	}
-	return numbers, nil
-}
-
-// listServices returns the names of services this server exposes.
-func (s *serverReflectionServer) listServices() []*v1reflectionpb.ServiceResponse {
-	serviceInfo := s.s.GetServiceInfo()
-	resp := make([]*v1reflectionpb.ServiceResponse, 0, len(serviceInfo))
-	for svc := range serviceInfo {
-		resp = append(resp, &v1reflectionpb.ServiceResponse{Name: svc})
-	}
-	sort.Slice(resp, func(i, j int) bool {
-		return resp[i].Name < resp[j].Name
-	})
-	return resp
-}
-
-// ServerReflectionInfo is the reflection service handler.
-func (s *serverReflectionServer) ServerReflectionInfo(stream v1reflectiongrpc.ServerReflection_ServerReflectionInfoServer) error {
-	sentFileDescriptors := make(map[string]bool)
-	for {
-		in, err := stream.Recv()
-		if err == io.EOF {
-			return nil
-		}
-		if err != nil {
-			return err
-		}
-
-		out := &v1reflectionpb.ServerReflectionResponse{
-			ValidHost:       in.Host,
-			OriginalRequest: in,
-		}
-		switch req := in.MessageRequest.(type) {
-		case *v1reflectionpb.ServerReflectionRequest_FileByFilename:
-			var b [][]byte
-			fd, err := s.descResolver.FindFileByPath(req.FileByFilename)
-			if err == nil {
-				b, err = s.fileDescWithDependencies(fd, sentFileDescriptors)
-			}
-			if err != nil {
-				out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_ErrorResponse{
-					ErrorResponse: &v1reflectionpb.ErrorResponse{
-						ErrorCode:    int32(codes.NotFound),
-						ErrorMessage: err.Error(),
-					},
-				}
-			} else {
-				out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_FileDescriptorResponse{
-					FileDescriptorResponse: &v1reflectionpb.FileDescriptorResponse{FileDescriptorProto: b},
-				}
-			}
-		case *v1reflectionpb.ServerReflectionRequest_FileContainingSymbol:
-			b, err := s.fileDescEncodingContainingSymbol(req.FileContainingSymbol, sentFileDescriptors)
-			if err != nil {
-				out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_ErrorResponse{
-					ErrorResponse: &v1reflectionpb.ErrorResponse{
-						ErrorCode:    int32(codes.NotFound),
-						ErrorMessage: err.Error(),
-					},
-				}
-			} else {
-				out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_FileDescriptorResponse{
-					FileDescriptorResponse: &v1reflectionpb.FileDescriptorResponse{FileDescriptorProto: b},
-				}
-			}
-		case *v1reflectionpb.ServerReflectionRequest_FileContainingExtension:
-			typeName := req.FileContainingExtension.ContainingType
-			extNum := req.FileContainingExtension.ExtensionNumber
-			b, err := s.fileDescEncodingContainingExtension(typeName, extNum, sentFileDescriptors)
-			if err != nil {
-				out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_ErrorResponse{
-					ErrorResponse: &v1reflectionpb.ErrorResponse{
-						ErrorCode:    int32(codes.NotFound),
-						ErrorMessage: err.Error(),
-					},
-				}
-			} else {
-				out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_FileDescriptorResponse{
-					FileDescriptorResponse: &v1reflectionpb.FileDescriptorResponse{FileDescriptorProto: b},
-				}
-			}
-		case *v1reflectionpb.ServerReflectionRequest_AllExtensionNumbersOfType:
-			extNums, err := s.allExtensionNumbersForTypeName(req.AllExtensionNumbersOfType)
-			if err != nil {
-				out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_ErrorResponse{
-					ErrorResponse: &v1reflectionpb.ErrorResponse{
-						ErrorCode:    int32(codes.NotFound),
-						ErrorMessage: err.Error(),
-					},
-				}
-			} else {
-				out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_AllExtensionNumbersResponse{
-					AllExtensionNumbersResponse: &v1reflectionpb.ExtensionNumberResponse{
-						BaseTypeName:    req.AllExtensionNumbersOfType,
-						ExtensionNumber: extNums,
-					},
-				}
-			}
-		case *v1reflectionpb.ServerReflectionRequest_ListServices:
-			out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_ListServicesResponse{
-				ListServicesResponse: &v1reflectionpb.ListServiceResponse{
-					Service: s.listServices(),
-				},
-			}
-		default:
-			return status.Errorf(codes.InvalidArgument, "invalid MessageRequest: %v", in.MessageRequest)
-		}
-
-		if err := stream.Send(out); err != nil {
-			return err
-		}
+	return &internal.ServerReflectionServer{
+		S:            opts.Services,
+		DescResolver: opts.DescriptorResolver,
+		ExtResolver:  opts.ExtensionResolver,
 	}
 }
diff --git a/reflection/test/go.mod b/reflection/test/go.mod
new file mode 100644
index 0000000..3fe34c8
--- /dev/null
+++ b/reflection/test/go.mod
@@ -0,0 +1,18 @@
+module google.golang.org/grpc/reflection/test
+
+go 1.19
+
+replace google.golang.org/grpc => ../../
+
+require (
+	github.com/golang/protobuf v1.5.4
+	google.golang.org/grpc v0.0.0-00010101000000-000000000000
+	google.golang.org/protobuf v1.33.0
+)
+
+require (
+	golang.org/x/net v0.22.0 // indirect
+	golang.org/x/sys v0.18.0 // indirect
+	golang.org/x/text v0.14.0 // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect
+)
diff --git a/reflection/test/go.sum b/reflection/test/go.sum
new file mode 100644
index 0000000..1e20865
--- /dev/null
+++ b/reflection/test/go.sum
@@ -0,0 +1,13 @@
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
+golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
+golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
+golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
+google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
+google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
diff --git a/reflection/grpc_testing_not_regenerate/README.md b/reflection/test/grpc_testing_not_regenerate/README.md
similarity index 100%
rename from reflection/grpc_testing_not_regenerate/README.md
rename to reflection/test/grpc_testing_not_regenerate/README.md
diff --git a/reflection/grpc_testing_not_regenerate/dynamic.go b/reflection/test/grpc_testing_not_regenerate/dynamic.go
similarity index 100%
rename from reflection/grpc_testing_not_regenerate/dynamic.go
rename to reflection/test/grpc_testing_not_regenerate/dynamic.go
diff --git a/reflection/grpc_testing_not_regenerate/dynamic.proto b/reflection/test/grpc_testing_not_regenerate/dynamic.proto
similarity index 100%
rename from reflection/grpc_testing_not_regenerate/dynamic.proto
rename to reflection/test/grpc_testing_not_regenerate/dynamic.proto
diff --git a/reflection/grpc_testing_not_regenerate/testv3.go b/reflection/test/grpc_testing_not_regenerate/testv3.go
similarity index 100%
rename from reflection/grpc_testing_not_regenerate/testv3.go
rename to reflection/test/grpc_testing_not_regenerate/testv3.go
diff --git a/reflection/grpc_testing_not_regenerate/testv3.proto b/reflection/test/grpc_testing_not_regenerate/testv3.proto
similarity index 100%
rename from reflection/grpc_testing_not_regenerate/testv3.proto
rename to reflection/test/grpc_testing_not_regenerate/testv3.proto
diff --git a/reflection/serverreflection_test.go b/reflection/test/serverreflection_test.go
similarity index 90%
rename from reflection/serverreflection_test.go
rename to reflection/test/serverreflection_test.go
index 26f3398..40257f1 100644
--- a/reflection/serverreflection_test.go
+++ b/reflection/test/serverreflection_test.go
@@ -16,7 +16,7 @@
  *
  */
 
-package reflection
+package test
 
 import (
 	"context"
@@ -30,6 +30,8 @@
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/credentials/insecure"
 	"google.golang.org/grpc/internal/grpctest"
+	"google.golang.org/grpc/reflection"
+	"google.golang.org/grpc/reflection/internal"
 	"google.golang.org/protobuf/proto"
 	"google.golang.org/protobuf/reflect/protodesc"
 	"google.golang.org/protobuf/reflect/protoreflect"
@@ -40,13 +42,12 @@
 	v1reflectiongrpc "google.golang.org/grpc/reflection/grpc_reflection_v1"
 	v1reflectionpb "google.golang.org/grpc/reflection/grpc_reflection_v1"
 	v1alphareflectiongrpc "google.golang.org/grpc/reflection/grpc_reflection_v1alpha"
-	v1alphareflectionpb "google.golang.org/grpc/reflection/grpc_reflection_v1alpha"
 	pb "google.golang.org/grpc/reflection/grpc_testing"
-	pbv3 "google.golang.org/grpc/reflection/grpc_testing_not_regenerate"
+	pbv3 "google.golang.org/grpc/reflection/test/grpc_testing_not_regenerate"
 )
 
 var (
-	s = NewServerV1(ServerOptions{}).(*serverReflectionServer)
+	s = reflection.NewServerV1(reflection.ServerOptions{}).(*internal.ServerReflectionServer)
 	// fileDescriptor of each test proto file.
 	fdProto2Ext  *descriptorpb.FileDescriptorProto
 	fdProto2Ext2 *descriptorpb.FileDescriptorProto
@@ -132,7 +133,7 @@
 		{"grpc.testing.ToBeExtended", 23, fdProto2Ext2},
 		{"grpc.testing.ToBeExtended", 29, fdProto2Ext2},
 	} {
-		fd, err := s.fileDescEncodingContainingExtension(test.st, test.extNum, map[string]bool{})
+		fd, err := s.FileDescEncodingContainingExtension(test.st, test.extNum, map[string]bool{})
 		if err != nil {
 			t.Errorf("fileDescContainingExtension(%q) return error: %v", test.st, err)
 			continue
@@ -162,7 +163,7 @@
 	}{
 		{"grpc.testing.ToBeExtended", []int32{13, 17, 19, 23, 29}},
 	} {
-		r, err := s.allExtensionNumbersForTypeName(test.st)
+		r, err := s.AllExtensionNumbersForTypeName(test.st)
 		sort.Sort(intArray(r))
 		if err != nil || !reflect.DeepEqual(r, test.want) {
 			t.Errorf("allExtensionNumbersForType(%q) = %v, %v, want %v, <nil>", test.st, r, err, test.want)
@@ -297,14 +298,14 @@
 		},
 	} {
 		t.Run(test.name, func(t *testing.T) {
-			s := NewServerV1(ServerOptions{}).(*serverReflectionServer)
+			s := reflection.NewServerV1(reflection.ServerOptions{}).(*internal.ServerReflectionServer)
 
 			sent := map[string]bool{}
 			for _, path := range test.sent {
 				sent[path] = true
 			}
 
-			descriptors, err := s.fileDescWithDependencies(test.root, sent)
+			descriptors, err := s.FileDescWithDependencies(test.root, sent)
 			if len(test.expect) == 0 {
 				// if we're not expecting any files then we're expecting an error
 				if err == nil {
@@ -407,7 +408,7 @@
 	registerDynamicProto(s, fdDynamic, fdDynamicFile)
 
 	// Register reflection service on s.
-	Register(s)
+	reflection.Register(s)
 	go s.Serve(lis)
 	t.Cleanup(s.Stop)
 
@@ -843,7 +844,7 @@
 }
 
 func (s v1AlphaClientStreamAdapter) Send(request *v1reflectionpb.ServerReflectionRequest) error {
-	return s.ServerReflection_ServerReflectionInfoClient.Send(v1ToV1AlphaRequest(request))
+	return s.ServerReflection_ServerReflectionInfoClient.Send(internal.V1ToV1AlphaRequest(request))
 }
 
 func (s v1AlphaClientStreamAdapter) Recv() (*v1reflectionpb.ServerReflectionResponse, error) {
@@ -851,58 +852,5 @@
 	if err != nil {
 		return nil, err
 	}
-	return v1AlphaToV1Response(resp), nil
-}
-
-func v1AlphaToV1Response(v1alpha *v1alphareflectionpb.ServerReflectionResponse) *v1reflectionpb.ServerReflectionResponse {
-	var v1 v1reflectionpb.ServerReflectionResponse
-	v1.ValidHost = v1alpha.ValidHost
-	if v1alpha.OriginalRequest != nil {
-		v1.OriginalRequest = v1AlphaToV1Request(v1alpha.OriginalRequest)
-	}
-	switch mr := v1alpha.MessageResponse.(type) {
-	case *v1alphareflectionpb.ServerReflectionResponse_FileDescriptorResponse:
-		if mr != nil {
-			v1.MessageResponse = &v1reflectionpb.ServerReflectionResponse_FileDescriptorResponse{
-				FileDescriptorResponse: &v1reflectionpb.FileDescriptorResponse{
-					FileDescriptorProto: mr.FileDescriptorResponse.GetFileDescriptorProto(),
-				},
-			}
-		}
-	case *v1alphareflectionpb.ServerReflectionResponse_AllExtensionNumbersResponse:
-		if mr != nil {
-			v1.MessageResponse = &v1reflectionpb.ServerReflectionResponse_AllExtensionNumbersResponse{
-				AllExtensionNumbersResponse: &v1reflectionpb.ExtensionNumberResponse{
-					BaseTypeName:    mr.AllExtensionNumbersResponse.GetBaseTypeName(),
-					ExtensionNumber: mr.AllExtensionNumbersResponse.GetExtensionNumber(),
-				},
-			}
-		}
-	case *v1alphareflectionpb.ServerReflectionResponse_ListServicesResponse:
-		if mr != nil {
-			svcs := make([]*v1reflectionpb.ServiceResponse, len(mr.ListServicesResponse.GetService()))
-			for i, svc := range mr.ListServicesResponse.GetService() {
-				svcs[i] = &v1reflectionpb.ServiceResponse{
-					Name: svc.GetName(),
-				}
-			}
-			v1.MessageResponse = &v1reflectionpb.ServerReflectionResponse_ListServicesResponse{
-				ListServicesResponse: &v1reflectionpb.ListServiceResponse{
-					Service: svcs,
-				},
-			}
-		}
-	case *v1alphareflectionpb.ServerReflectionResponse_ErrorResponse:
-		if mr != nil {
-			v1.MessageResponse = &v1reflectionpb.ServerReflectionResponse_ErrorResponse{
-				ErrorResponse: &v1reflectionpb.ErrorResponse{
-					ErrorCode:    mr.ErrorResponse.GetErrorCode(),
-					ErrorMessage: mr.ErrorResponse.GetErrorMessage(),
-				},
-			}
-		}
-	default:
-		// no value set
-	}
-	return &v1
+	return internal.V1AlphaToV1Response(resp), nil
 }
diff --git a/scripts/vet.sh b/scripts/vet.sh
index 236e1ef..74690e8 100755
--- a/scripts/vet.sh
+++ b/scripts/vet.sh
@@ -61,7 +61,7 @@
 git grep -l -e 'grpclog.I' --or -e 'grpclog.W' --or -e 'grpclog.E' --or -e 'grpclog.F' --or -e 'grpclog.V' -- "*.go" | not grep -v '^grpclog/component.go\|^internal/grpctest/tlogger_test.go'
 
 # - Ensure that the deprecated protobuf dependency is not used.
-not git grep "\"github.com/golang/protobuf/*" -- "*.go" ':(exclude)reflection/grpc_testing_not_regenerate/*'
+not git grep "\"github.com/golang/protobuf/*" -- "*.go" ':(exclude)reflection/test/grpc_testing_not_regenerate/*'
 
 # - Ensure all usages of grpc_testing package are renamed when importing.
 not git grep "\(import \|^\s*\)\"google.golang.org/grpc/interop/grpc_testing" -- "*.go"