Skip to content

Instantly share code, notes, and snippets.

@akihisa-shimada
Created August 24, 2023 10:38
Show Gist options
  • Save akihisa-shimada/366d4427c46349fb6ae7d54f7b440a17 to your computer and use it in GitHub Desktop.
Save akihisa-shimada/366d4427c46349fb6ae7d54f7b440a17 to your computer and use it in GitHub Desktop.
package com.example.proto.grpc.exception.message;
import com.google.protobuf.Message;
import io.grpc.Status;
import java.util.LinkedHashMap;
import java.util.Objects;
/**
* 特定のgRPCレスポンスのための例外クラスです。
*
* @see org.springframework.web.server.ResponseStatusException
*/
public class ResponseStatusException extends RuntimeException {
final Status status;
LinkedHashMap<String, Object[]> messageKeys;
LinkedHashMap<String, Object[]> detailKeys;
public ResponseStatusException(Status status, String message) {
super(message);
this.status = status;
this.messageKeys = null;
this.detailKeys = null;
}
public ResponseStatusException(Status status, String message, Throwable cause) {
super(message, cause);
this.status = status;
this.messageKeys = null;
this.detailKeys = null;
}
public ResponseStatusException(Status status, LinkedHashMap<String, Object[]> messageKeys, LinkedHashMap<String, Object[]> detailKeys) {
super();
this.status = status;
this.messageKeys = messageKeys;
this.detailKeys = detailKeys;
}
public Status getStatus() {
return status;
}
public LinkedHashMap<String, Object[]> getMessageKeys() {
return messageKeys;
}
public LinkedHashMap<String, Object[]> getDetailKeys() {
return detailKeys;
}
}
package com.example.proto.grpc.exception.message;
import io.grpc.Status;
/**
* 特定のgRPCレスポンスのための例外クラスです。
*
* @see org.springframework.web.server.ResponseStatusException
*/
public class ResponseStatusException extends RuntimeException {
final Status status;
public ResponseStatusException(Status status, String message) {
super(message);
this.status = status;
}
public ResponseStatusException(Status status, String message, Throwable cause) {
super(message, cause);
this.status = status;
}
public Status getStatus() {
return status;
}
}
package com.example.proto.grpc.exception.message;
import com.google.protobuf.Message;
import com.google.rpc.LocalizedMessage;
/**
* エラーメッセージの詳細を扱います
*/
public interface DetailMessage {
/**
* メッセージを返却します
*
* @return protobuf message class
*/
Message getMessage();
/**
* protobufのメッセージを直接扱います
*/
class RawMessage implements DetailMessage {
Message message;
RawMessage(Message message) {
this.message = message;
}
@Override
public Message getMessage() {
return message;
}
}
/**
* テンプレート化されたメッセージを扱います
*/
interface TemplateMessage extends DetailMessage {
Message getMessage(MessageResolver messageResolver);
@Override
default Message getMessage() {
throw new UnsupportedOperationException("Unsupported the retrieval of raw message.");
}
/**
* テンプレート化されたLocalizedMessageを扱います
*/
class LocalizedMessageTemplateMessage implements TemplateMessage {
String templateMessage;
Object[] parameters;
LocalizedMessageTemplateMessage(String templateMessage, Object... parameters) {
this.templateMessage = templateMessage;
this.parameters = parameters;
}
@Override
public Message getMessage(MessageResolver messageResolver) {
return LocalizedMessage.newBuilder()
.setLocale(messageResolver.getLocale().toString())
.setMessage(messageResolver.getMessage(templateMessage, parameters))
.build();
}
}
}
}
package com.example.proto.grpc.exception.message;
import com.google.protobuf.Message;
import java.util.HashSet;
import java.util.Set;
/**
* DetailMessageのためのユーティリティクラス
*/
public class DetailMessages {
/**
* protobufで定義されたMessageクラス用のBuilderクラスを生成します
*
* @return protobuf Messageクラス用のBuilderクラス
*/
public static RawMessageDetailMessageBuilder rawMessageBuilder() {
return new RawMessageDetailMessageBuilder();
}
/**
* LocalizedMessageのTemplateMessageクラス用のBuilderクラスを生成します
*
* @return LocalizedMessageのTemplateMessageクラス用のBuilderクラス
*/
public static LocalizedMessageDetailMessageBuilder localizedMessageBuilder() {
return new LocalizedMessageDetailMessageBuilder();
}
/**
* テンプレートメッセージを利用したDetailMessageを生成します。
* このメソッドは、{@link DetailMessages#localizedMessageBuilder()}のショートカットメソッドです。
*
* @param templateMessage テンプレートメッセージ
* @param parameters テンプレートにセットする変数
* @return 単一のLocalizedMessage
*/
public static Set<DetailMessage> localizedMessage(String templateMessage, Object... parameters) {
return localizedMessageBuilder()
.add(templateMessage, parameters)
.build();
}
public static class LocalizedMessageDetailMessageBuilder {
Set<DetailMessage> messages;
/**
* DetailMessagesを利用して生成するため、パッケージプライベートとします。
*/
LocalizedMessageDetailMessageBuilder() {
this.messages = new HashSet<>();
}
public LocalizedMessageDetailMessageBuilder add(String templateMessage, Object... parameters) {
messages.add(new DetailMessage.TemplateMessage.LocalizedMessageTemplateMessage(templateMessage, parameters));
return this;
}
public Set<DetailMessage> build() {
return messages;
}
}
public static class RawMessageDetailMessageBuilder {
Set<DetailMessage> messages;
/**
* DetailMessagesを利用して生成するため、パッケージプライベートとします。
*/
RawMessageDetailMessageBuilder() {
this.messages = new HashSet<>();
}
public RawMessageDetailMessageBuilder add(Message message) {
messages.add(new DetailMessage.TemplateMessage.RawMessage(message));
return this;
}
public Set<DetailMessage> build() {
return messages;
}
}
}
package com.example.proto.grpc.exception.message;
import com.example.proto.grpc.exception.message.DetailMessage;
import com.example.proto.grpc.exception.message.MessageResolver;
import com.google.protobuf.Message;
import io.grpc.Status;
import java.util.Collections;
import java.util.Set;
import static java.util.stream.Collectors.toSet;
/**
* 特定のgRPCレスポンスのための例外クラスです。
*
* @see org.springframework.web.server.ResponseStatusException
*/
public class ResponseStatusException extends RuntimeException {
final Status status;
final Set<DetailMessage> detailMessages;
public ResponseStatusException(Status status, String message) {
super(message);
this.status = status;
this.detailMessages = Collections.emptySet();
}
public ResponseStatusException(Status status, String message, Throwable cause) {
super(message, cause);
this.status = status;
this.detailMessages = Collections.emptySet();
}
public ResponseStatusException(Status status, String message, Set<DetailMessage> detailMessages) {
super(message);
this.status = status;
this.detailMessages = detailMessages;
}
public Status getStatus() {
return status;
}
public Set<? extends Message> getDetails(MessageResolver messageResolver) {
return detailMessages.stream()
.map(detail -> {
if (detail instanceof DetailMessage.TemplateMessage) {
DetailMessage.TemplateMessage templateMessage = (DetailMessage.TemplateMessage) detail;
return templateMessage.getMessage(messageResolver);
} else {
return detail.getMessage();
}
}).collect(toSet());
}
}
package com.example.proto.grpc.exception.message;
import org.springframework.lang.Nullable;
import java.util.Locale;
/**
* テンプレート化されたメッセージの変換を扱います
*/
public interface MessageResolver {
String getMessage(String code, @Nullable Object[] args);
Locale getLocale();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment