AWS – API Gateway to create data in DynamoDB through Lambda function in Java

By Nobukimi Sasaki (2023-04-24) Continued from API Gateway + Lambda + DynamoDB (Configuration)

Dependency for AWS Lambda

        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-lambda-java-core</artifactId>
            <version>1.1.0</version>
        </dependency>
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-lambda-java-events</artifactId>
            <version>2.0.2</version>
        </dependency>
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-java-sdk-dynamodb</artifactId>
            <version>1.11.271</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.14.1</version>
        </dependency>

The main class receive the request:APIGatewayProxyRequestEvent::getHttpMethod.

import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBScanExpression;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;

public class LambdaHandler implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {

    @Override
    public APIGatewayProxyResponseEvent handleRequest ( APIGatewayProxyRequestEvent apiGatewayRequest, Context context ) {

        EmployeeService employeeService = new EmployeeService();

        switch (apiGatewayRequest.getHttpMethod()) {

            case "POST":
                return employeeService.saveEmployee( apiGatewayRequest, context );

            case "GET":
                if (apiGatewayRequest.getPathParameters() != null) {
                    return employeeService.getEmployeeById( apiGatewayRequest, context );
                }
                return employeeService.getEmployees( apiGatewayRequest, context );
            case "DELETE":
                if (apiGatewayRequest.getPathParameters() != null) {
                    return employeeService.deleteEmployeeById( apiGatewayRequest, context );
                }
            default:
                throw new Error( "Unsupported Methods:::" + apiGatewayRequest.getHttpMethod() );

        }
    }
}

The 1st parameter, APIGatewayProxyRequestEvent contains:
This getHttpMethod returns String httpMethod that is “GET”, “POST”, “PUT”,,,,

The 2nd parameter, Context contains:

The response class “APIGatewayProxyResponseEvent” contains:

Saving data:

import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBScanExpression;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
import com.app.easy2excel.entity.Employee;

import java.util.List;
import java.util.Map;

public class EmployeeService {

    private DynamoDBMapper dynamoDBMapper;
    private static String jsonBody = null;

    public APIGatewayProxyResponseEvent saveEmployee ( APIGatewayProxyRequestEvent apiGatewayRequest, Context context ) {
        initDynamoDB();
        Employee employee = Utility.convertStringToObj( apiGatewayRequest.getBody(), context );
        dynamoDBMapper.save( employee );
        jsonBody = Utility.convertObjToString( employee, context );
        context.getLogger().log( "data saved successfully to dynamodb:::" + jsonBody );
        return createAPIResponse( jsonBody, 201, Utility.createHeaders() );
    }
....

Within the createAPIResponse, it returns the APIGatewayProxyResponseEvent:

    private APIGatewayProxyResponseEvent createAPIResponse ( String body, int statusCode, Map<String, String> headers ) {
        APIGatewayProxyResponseEvent responseEvent = new APIGatewayProxyResponseEvent();
        responseEvent.setBody( body );
        responseEvent.setHeaders( headers );
        responseEvent.setStatusCode( statusCode );
        return responseEvent;
    }

The entity model:

import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;

@DynamoDBTable(tableName = "employee")
public class Employee {

    @DynamoDBHashKey(attributeName = "empId")
    private String empId;

    @DynamoDBAttribute(attributeName = "name")
    private String name;

    @DynamoDBAttribute(attributeName = "email")
    private String email;
....

How to deploy the code:
Go to intellij terminal, as command line >mvn clean install

The jar file is created under target:

After specifying the built jar file, then upload.
Lambda > Functions > RestApiLambda (your function name) … There is a “Upload From” button:

Scroll down and under Runtime settings > Edit

Edit the header info as:

1. Package path
2. Class name
3. Method name
Then Save! Now the API is ready to run

In Postman, the POST request went succesfully:


Go to dashboard DynamoDB > Tables

1. Tables
2. Check
3. Click the table name
4. Explore the items
5. You will see the data created

AWS – API Gateway + Lambda + DynamoDB (Configuration)

By Nobukimi Sasaki (2023-04-24)

Create Dynamo DB

In AWS management console, pick Dynamo DB. In this example, the table name is “employee”. Give the primary key name “empId” in String.

Create Lambda Function:

In AWS management console, pick Lambda, then “Create function”. In this example, “RestApiLambda”.
The Runtime, “Java 11”, the table name is “employee”. Give the primary key name “empId” in String.

Providing a role:

Go to “IMA” console, choose “Lambda”, set the permission to “AmazonDynamoDBFullAccess”, “AWSLambdaBasicExecutionRole”.
Give the role name. In this example, “crudAPIRole”. After creating the role, check “use existing role”, and “Create function”.

Create API Gateway:

In AWS management console, pick “API Gateway”. Choose protocol “REST” and “New API”. In this example, API name is “EmployeeAPI”.

Specify the “Resources” for the API:

Under “API:EmployeeAPI”, click “Resource” then set the name “employee” it make the path …/employee as URL.
Check Enable API Gateway CORS.


1. Click the name of the resource (“employee” in this example)
2. Create Method
3. Select “POST” depends in the type.
4. Check this
5. Lambda Function
6. Use Lambda Proxy Integration
7. Type the name of function you have created (“RestApiLambda” in this example)
8. Save


1. Action
2. Deploy API
3. New Stage
4. dev (environment)
5. Deploy


After deployed, this is the URL for the API.

Microservices with Kafka

By Nobukimi Sasaki (2023-04-23)

Introduction:
This is my study note composed of three services (Spring Boot) with a message broker (kafka).
There services are independent to each other and communicating asynchronously.

Entire project structure:
There are four Spring Boots project under one folder

Service A: order-service
Whenever receiving the HTTP request, the order-service create a event and publish the event to the message broker (Kafka).

Service B (stock-service) & C (email-service)
Just consume the message from the message broker (Kafka) and Service B & C don’t know about Service A (order-service). They are all independent to each other.

Spring Boot for DTO object (base-domains)
The DTO classes for the message that being referred from Service A, B, and C.

Service A – order-service detail:

1. OrderController::placeOrder receives the request from HTTP client
2. OrderController::placeOrder::sendMessage calls Kakfa Producer
3. OrderProducer::sendMessage calls KafkaTemplate::send

spring.kafka.producer.bootstrap-servers: localhost:9092
spring.kafka.producer.key-serializer: org.apache.kafka.common.serialization.StringSerializer
spring.kafka.producer.value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
spring.kafka.topic.name=order_topics

At Service A, this property configures a Kafka Server (line 1), and topic name (line 4)

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.kafka</groupId>
			<artifactId>spring-kafka</artifactId>
		</dependency>
		<dependency>
			<groupId>net.javaguides</groupId>
			<artifactId>base-domains</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.kafka</groupId>
			<artifactId>spring-kafka-test</artifactId>
			<scope>test</scope>
		</dependency>

At Service A, B, and C, the dependency is Kakfa and DTO project (base-domains)

import net.javaguides.basedomains.dto.Order;
import net.javaguides.basedomains.dto.OrderEvent;
import net.javaguides.orderservice.kafka.OrderProducer;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;

@RestController
@RequestMapping("/api/v1")
public class OrderController {

    private OrderProducer orderProducer;

    public OrderController(OrderProducer orderProducer) {
        this.orderProducer = orderProducer;
    }

    // Rest End Point API for testing
    @PostMapping("/orders")
    public String placeOrder(@RequestBody Order order){

        order.setOrderId(UUID.randomUUID().toString());

        OrderEvent orderEvent = new OrderEvent();
        orderEvent.setStatus("PENDING");
        orderEvent.setMessage("order status is in pending state");
        orderEvent.setOrder(order);

        orderProducer.sendMessage(orderEvent);

        return "Order placed successfully ...";
    }
}

At Service A, OrderController::placeOrder receives the request from HTTP client, and sendMessage calls Kakfa Producer

import net.javaguides.basedomains.dto.OrderEvent;

import org.apache.kafka.clients.admin.NewTopic;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.support.KafkaHeaders;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;

@Service
public class OrderProducer {

    private static final Logger LOGGER = LoggerFactory.getLogger(OrderProducer.class);

    private NewTopic topic;

    private KafkaTemplate<String, OrderEvent> kafkaTemplate;

    // Parameter constructor in this class
    public OrderProducer(NewTopic topic, KafkaTemplate<String, OrderEvent> kafkaTemplate) {
        this.topic = topic;
        this.kafkaTemplate = kafkaTemplate;
    }

    public void sendMessage(OrderEvent event){
        LOGGER.info(String.format("Order event => %s", event.toString()));

        // create Message
        Message<OrderEvent> message = MessageBuilder
                .withPayload(event)
                .setHeader(KafkaHeaders.TOPIC, topic.name())
                .build();
        kafkaTemplate.send(message);
    }
}

At Service A, OrderProducer::sendMessage calls KafkaTemplate::send

Service B (stock-service) and C (email-service) Service detail:

Service B (stock-service) and C (email-service) has kafka consumer to receive the message.

server.port=8081
spring.kafka.consumer.bootstrap-servers: localhost:9092
spring.kafka.consumer.group-id: stock
spring.kafka.consumer.auto-offset-reset: earliest
spring.kafka.consumer.key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
spring.kafka.consumer.value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
spring.kafka.consumer.properties.spring.json.trusted.packages=*
spring.kafka.topic.name=order_topics

At Service B (stock-service), Line 1 – the port is 8081, and group id is “stock”

server.port=8082
spring.kafka.consumer.bootstrap-servers: localhost:9092
spring.kafka.consumer.group-id: email
spring.kafka.consumer.auto-offset-reset: earliest
spring.kafka.consumer.key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
spring.kafka.consumer.value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
spring.kafka.consumer.properties.spring.json.trusted.packages=*
spring.kafka.topic.name=order_topics

At Service C (email-service), Line 1 – the port is 8082, and group id is “email”
Both Service B & C, Line 2 – register the kafka server port 9092, and line 8, the topic name of “order_topics”

import net.javaguides.basedomains.dto.OrderEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Service;

@Service
public class OrderConsumer {

    private static final Logger LOGGER = LoggerFactory.getLogger(OrderConsumer.class);

    @KafkaListener(
            topics = "${spring.kafka.topic.name}"
            ,groupId = "${spring.kafka.consumer.group-id}"
    )
    public void consume(OrderEvent event){
        LOGGER.info(String.format("Order event received in stock service => %s", event.toString()));

        // business logic
    }
}

Both Service B & C have this consumer class.

DTO object (base-domains) Details:

This DTO classes are referenced from Service A, B, and C


Example of RESTFul client

Spring REST GET with HttpServletRequest

REST client:


import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.RestTemplate;

import com.ns.model.UdsTransactionRequest;
import com.ns.model.UfsReferenceNumber;
import com.ns.model.notification.UfsPipeline;
import com.ns.service.ServiceResponse;

	@SuppressWarnings("unchecked")
	private void testGet2() {

		RestTemplate restTemplate = new RestTemplate();

		Long txId = 123456789L;
		String[] array = {"6B","EL","SO","RN","KK"};

		String url = "http://localhost:8080/transaction/references/pipeline/{txId}/?types={types}";

		ServiceResponse<UfsReferenceNumber> response = restTemplate.getForObject(url, ServiceResponse.class, txId, StringUtils.join(array, ","));

		List<UfsReferenceNumber> results = response.getData();
		if (results != null && !results.isEmpty()) {
			for (UfsReferenceNumber a : results) {
				System.out.println("---------------- ID: " + a.getId().getRefNum());
			}
		}
		System.out.println("---------------- END testGet2------------------");
	}

This gives the URL:

http://localhost:8080/transaction/references/pipeline/123456789/?types=6B,EL,SO,RN,KK

The “request.getParameter(“types”);” gets the values from URL “types=6B,EL,SO,RN,KK”.

REST endpoint:

@RequestMapping(value = "/references/pipeline/{txId}/", method = RequestMethod.GET)
public ServiceResponse<UfsReferenceNumber> getReferences(@PathVariable String txId, HttpServletRequest request) {
	ServiceResponse<UfsReferenceNumber> response = new ServiceResponse<>();
	String typesCsv = request.getParameter("types");
	List<String> types = null;
	List<UfsReferenceNumber> references = null;
	if (null != typesCsv && 0 != typesCsv.length()) {
		types = Arrays.asList(typesCsv.split(","));
	}
	try {
		references = repo.getTxnReferenceNumbers(new Long(txId), types);
		if (null != references && !references.isEmpty()) {
			response.setData(references);
		}
	} catch (Exception e) {
	}
	return response;
}

Removed duplicated element

private List<SelectItem> getRemovedDupElements(List<SelectItem> list) {

	if (!list.isEmpty()) {
		Set<String> set = new HashSet<String>();
		List<SelectItem> newList = new ArrayList<SelectItem>();

		for (Iterator<SelectItem> iter = list.iterator(); iter.hasNext();) {
			SelectItem var = iter.next();
			String labelTemp = var.getLabel();
			if (set.add(labelTemp)) {
				newList.add(var);
			}
		}
		list.clear();
		return newList;
	}
	return list;
}

友人関係と政治

国民性というものは実際に付き合ってはじめて見えてくる部分が多い。これを書くのは気が重い部分もある。中国や韓国の友人達を裏切るような後ろめたさがあるが、友人関係と政治は切り離さなければいけない。自分の体験を将来の子供達へ伝えなければならない。

NYという場所がら、多くの国の人と触れ合う機会に恵まれたと思う。その中でも一番仲良くなり易いのは、意外にも韓国人だった。そしてそれは僕が近代史に興味を持つきっかけとなった。

アメリカに来て間もない頃、日本が海外ではどう思われているのか気になっていた時期があった。日本では自虐的な歴史ばかり教えられていたせいで、日本人は嫌われているのではないかと不安な部分もあったからだ。結論としては日本人は特別尊敬もされていないが、決してバカにされてはいない。どちらかといえば一目置かれていると感じる。

世界の国で日本を嫌っているのは中国、韓国、北朝鮮の3カ国のみと言っていい。しかもこの3カ国はすべて言論統制国家なのである。北朝鮮はもちろん、中国でも政治に関することを自由に発言できない。民主主義国家の韓国はどうかといえば、政府にとって都合が悪い発言、行動をすれば、下手すれば逮捕されるということが最近ニュースで話題になっている。言論統制が行われていることに疑いの余地はない。「親日派」と思われるだけで自分の身が危険にさらされるのだ。戦中の日本で「反戦派」と思われれば「スパイ」と言われ逮捕されたのと似ている。現在の日本では「軍国主義者」と思われても少なくとも逮捕されることはない。このことからも反日国家の人たちの言っていることをとても鵜呑みには出来ないことが分かる。

韓国と同じように日本の植民地だった台湾は完全な親日の国だといえる。同じように日本に統治されてなぜここまで違ってしまうのだろうか。理由は簡単に説明できるものではないが、ひとつはそれぞれ歩んできた歴史が関わっている。

韓国は数千年前から王朝があり日本より文明が上だったとされている。それを結果として日本が終わらせてしまったのだ。彼らのプライドを踏みにじったのは確かだといえる。台湾はもともと未開に地だったが日本の統治時代に近代国家の基礎を築いた。でも戦後、中国から逃げてきた国民党に統治されたが日本に支配された時代のほうがマシだったと思っている人が大勢いる。台湾は親日派が大勢いる国なのである。

反日国家の中国と韓国では反日のニュアンスが多少異なり、中国はかつて日本と戦争したことから来る反日であり、韓国は日本に植民地支配されていたことを恨んだ反日という違いがある。中国人よりも、韓国人のほうが日本に対して過剰に意識しているようである。反日感情と同時に興味を抱いているようだ。

個人として付き合えば意外に仲良くできるものである。(もちろん全ての人ではないが)特に韓国人は人懐っこい人が多い。韓国人と日本人の違いを一言で言い表すなら、日本人から見れば韓国人は「わがまま」と感じ、韓国人からみれば日本人は「冷たい」と感じるようだ。けっこうこれは的を得ていると思う。

日本人と韓国人の国民性

アメリカに来て以来多くの韓国人を見てきた。日本人以外で一番仲良くなり易い外国人ではないかと思う。アメリカに来て間もないころ、韓国人の知人と話し合った時に両国民性の違いについて話し合った。韓国人は「わがまま」で日本人は「冷たい」という印象をお互いに認め合ったが、今も的を得た表現だと思っている。

肯定的に表現するとどうなるか。韓国人は「日本人より情に熱い」と言ったところか。では「日本人は比較的素直な人が多く、争いを好まない」とでも言い換えることも出来る。

日本人と韓国人は似ているところもあるが、明らかな相違点もある。日本人にはない部分だと感じた部分をまとめてみると以下のようになった。

1.愛国心が強い
2.自己主張が強い、文句が多い、喧嘩っ早い
3.儒教の影響が日本より強い
4.人懐っこい、温かみがある
5.日本をかなり意識している

僕がアメリカに来たのは90年代半ばだった。当時の自分は歴史や世界情勢に疎く韓国、中国、台湾、香港、その他アジアの国の違さえよくわかってい無様なものであった。それに対して韓国人は総じて日本のことを良く知っていて驚いた。日本の有名人、アニメ、映画、日本語の単語をよく知っていた。韓国語と日本語は文法が殆ど同じで、韓国人は日本語を勉強する人が多いということ知った。NYには韓国系の食品店があちこちにあるが、日本で売っているお菓子をそのまま韓国版にしたようなもが非常に多かった。これは日本か韓国のどちらかがコピーしたのだろうがおそらくは後者だと思われる。

これは当時韓国人留学生の知人から聞いた話であるが、韓国ではテレビ番組やアニメを日本のものをコピーしたものが多いが、原作者は通常韓国人の名前に置き換わっていて、日本の原作だということは隠す傾向があるという。最近ネットでよく目にする「韓国起源説」文化と重なる部分が見えなくもないが、これは日本の番組が法律で禁止されていたのも関係しているかもしれない。ただ、意外にも多くの韓国人はそれらを日本からコピーしたのだと知っているようだ。

日本も明治以来、欧米のものを真似してきたのでそれに対してどうこう言える立場ではないが、原作者を自国の人間に置き換えるという習慣はないと思う。アメリカでは”Power Rangers” という、日本の「スーパー戦隊」シリーズを真似た子供向けの人気番組があるが、堂々と「日本のスーパー戦隊シリーズのコピーだ」と公言している。アメリカの大学では、レポートやプロジェクトをコピー(盗作)することは、”Plagiarism”と呼ばれ「犯罪」扱いとされ、最悪退学となることもある。だから盗作には寛容ではない。それに対して、韓国では「日本のコピーだ」と公言することは殆どあり得ないと思われる。なぜなら国民感情を逆なですることになるからだ。「反日無罪」という文化もあり、犯罪とみなされる行為でも反日イコール愛国の為とみなされる傾向があるという。

日本と韓国はには共通の文化が結構あるように思えるが、それらの多くは儒教の影響があるように見える。例えば、男尊女卑をはじめ、先輩、後輩という考え方があるが、アメリカではそのような考え方はない。年上に対して敬語で話すというのも日本語と韓国語に共通した部分であるがアメリカ英語にそういうものはない。「青春時代」という言葉も韓国にはあるが、アメリカ英語にはそれに相当する一般的な言葉はない。そのように日本語と韓国語は共通語が多い。これらの細かい共通点が韓国人が身近に感じる理由かもしれない。

日本も韓国も儒教の影響が今も残っているが、韓国のそれのほうが日本より強いように思える。韓国の食品店でおばさんに手で押しのけられたことがあるが、韓国人に言わせるとこちらが若いからそういうこともありえるという。日本ではそのようなことはない。

日本人と韓国人の大きな違いのひとつは自己主張の強さだと思う。自己主張が強いのは欧米人も同じであるが、韓国人の自己主張の特徴は、自分の価値観を押し通そうとするところだと思う。相手と喧嘩をすることを厭わないのである。喧嘩してはじめて相手と仲良くなれると考えている部分もあるそうだ。

大学の図書館のビルの前でタバコをすって数人でたむろしているアジア人はたいてい韓国人学生だった。韓国人は他の韓国人を知ろうとする。「韓国人学生はみんなお互いに知っている」と言う。日本人の場合は「アメリカに来てまで日本人と知り合いたくない」という人が多い。日本人はお互いを知ろうとしない。

韓国人は相手と深いつながりを求めるようだ。例えば恋人同士が相手の留守番電話メッセージをチェックして浮気していないか監視することも珍しくないという。日本人では考えられないことだ。日本人は「親しき中にも礼儀あり」という考えた方があるが韓国人にはそのような考え方はあまりないように思う。これは大きな違いといえる。

韓国人と一緒に食事をするとワリカンをしない傾向が強い。「今日は僕のおごりだから今度は君がおごってくれ」といった感じである。とにかく「一緒」が好きなのだ。これらの違いを見ると、韓国人からすると、「日本人は冷たい」と写り、日本人からみれば韓国人は「わがまま」と写るのが分かる。

日本は昔(鎌倉時代以降)から武士が社会を支配してきたが、韓国(朝鮮)は学者が支配してきたという。だから現在でも学閥は強く、出身大学の名前に非常に敏感であるように見える。日本もそうであるが韓国はそれ以上だと思える。大学名は彼らにとってブランドとなり、その価値は非常に高い。なにを勉強したかよりも、なんという名前の大学を出たかのほうが重要なのである。もっともこれは日本も近いものがあるかもしれない(笑)。ただ、教師の地位は日本よりはるかに高いようで憧れの職業だという。日本も韓国も教師を「先生」と呼ぶが、アメリカではミスターXX、ミセスXXと名前で呼ぶのが普通である。大学では”Professor”「教授」と呼ばれ尊敬のニュアンスを含むが”Teacher”に「先生」のような尊敬のニュアンスはない。

韓国人の友人らによると、韓国は昔から常に周りの大国からの脅威にさらされてきた。中国、ロシア、アメリカ、そして日本。だから強いものとうまく付き合う必要があったという。儒教の影響である上下関係がそれに拍車をかけているように思える。強いものに取り入って自分らを守るのが彼らの長年の歴史から備わった国民性であると思える。

アメリカの韓国人同士のネットワークは強い。彼らを繋げるものの一つはいうまでもなく愛国心でありその一部が残念ながら「反日」である。自分達の価値観を押し通そうとする特徴は「慰安婦の像」を建てるといった行動になって現れている。今まで多くの韓国人といい時間を過ごしてきた自分でさえ、見ず知らずの韓国人にはどうしても警戒感を抱いてしまう。残念なことだ。

竹林はるか遠く

アメリカに来て間もない頃、Boston在住の伯母に貰った本がある。So Far From Bamboo Grove 邦題 – 「竹林はるか遠く」という本で、著者が終戦時に現在の朝鮮半島から命からがら日本に逃げ帰った時の体験談だった。

なぜ、伯母がこの本を僕にくれたかというと、本の著者のヨーコ.・カワシマ・ワトキンス氏と知り合いだったからだ。ワトキンス氏と直接お目にかかったことはないが、僕宛の直筆のメッセージも書いて頂いていた。伯母からの配慮である。本は日本の実家に置いてあるので、メッセージの内容ははっきり覚えていないが、温かみのある彼女の人柄が感じられるものだったと記憶している。

そして月日は流れ、ある日、韓国のニュースサイトでこの本に関する記事を見て驚いた。「被害者と加害者を入れ替えている」と強い口調で非難しているのだ。日本人の自分からすれば特に韓国、朝鮮人を非難する内容などという内容ではまったくない。ワトキンス氏だってそのようなつもりで書いた気持ちは毛頭ない筈だ。それどころか親切な朝鮮人の話も出てくる。むしろ彼女の批判は当時の日本社会に向けられている。

しかし彼らの主張するところによると、朝鮮半島にソ連軍、朝鮮人の共産党軍による日本人に対する略奪、強姦の記述がありそれが気に入らないということらしい。なるほど確かに韓国人からすればあまり気分がいいものではないだろう。ただ、それは作り話ではなく実際の体験記なのである。一部の旧日本軍も略奪を行ったかもしれないが、ソ連人、朝鮮人、中国人だって行っているのだ。満州で日本の敗戦が決まった後、日本人に対する略奪行為があったことも事実なのである。
聞けばその本は在米韓国人たちの抗議によって公立学校の教科書から外されたらしい。Bostonの伯母に聞いたところによると、当時11歳だった子供の記憶は信憑性がないからというのが彼らの主張だったらしい。ワトキンス氏は「私は本当に体験したことを書いただけ」と記者会見まで開いたようだ。しかしその場で「でたらめだ」とアメリカ人の反日活動家につめよられたとか。お気の毒としか言いようがない。

抗議した在米韓国人は「子供の記憶は信憑性がない」という理由で教科書から外すように求めたというが、「被害者と加害者を入れ替えているのが気に入らないからだ」とは言わなかった。もちろんそのような理由ではアメリカの機関を納得させられなからである。彼らの行動は韓国のメディアで英雄的行動として取り上げられたという。
自分たちが書かれて気分が悪いものは排除するように求め、その一方で「慰安婦の像」のようなものを建てようと活発に活動している。彼らにとって日本は「悪」で自分たちは「被害者」であり、これは彼らの絶対的前提条件なのだ。まさしく思考停止状態である。疑問を持つ韓国人もいるというがそれを口に出すと韓国人として「非国民」扱いされるのでみな黙っているそうだ。もっとも日本人も似たようなものだが。

「従軍慰安婦問題」は吉田清治なる人物が朝日新聞に語ったことが発端となり、朝日新聞は2014年にそれを創作だったことを認めている。今では日本人の多くは事実だと思っていない。韓国では反日の行動は愛国心に基づいた英雄的行動と解釈される。彼らは被害者だから加害者の日本には何を言ってもいいと思っているのである。これが現実なのだ。教育とは恐ろしいものである。このような世界にいることを日本人は認識すべきだ。
歴史に興味を持つ程、一方的な加害者、被害者で説明できるほど単純なものではないことが分かる。彼らの主張する一方的は被害者意識が正常ではないことが分かる。日本人の子孫として生きていく子供達にはそのことを伝えなければならない。

最後に、僕はアメリカで今まで多くの韓国人と会い、彼らといい時間も共有してきた。その中で日本人と韓国人の国民性の違いも見てきた。この問題は彼らと築いた友人関係とは切り離して考えている。意外にも韓国人は日本人と感覚が近い部分があるというか、日本人以外でもっとも仲良くなりやすいと感じている。しかし友人関係は築けても歴史の問題はお互い譲れないことも分かっている。これが現実なのだ。

青い飛行機

私の二人の息子はアメリカで生まれ、日本とアメリカの両方の国籍を持っているが将来はおそらく心はアメリカ人となっていくだろう。

先日5歳の長男が戦闘機の動画が見たいといい、第二次大戦の日本とアメリカの空中戦を再現したヒストリーチャンネルを見せたところ「僕は青い飛行機が好き」と言う。
gramman-f6f-hellcat-1
「青い飛行機」とはアメリカ軍のF6F グラマン・ヘルキャットのことである。日本の零式艦上戦闘機、ゼロ戦のライバルである。そして、そのゼロ戦を指して「緑の飛行機は悪者」と言った。

アメリカが作成した番組だから余計にそう見えたのかもしれないが、長男は既に自分のことをアメリカ人だと思い始めているように感じた。最近は日本語も殆ど出なくなってしまった。こちらが日本語で話しかけても英語で応えるようになってきた。「僕はアメリカ人、パパとママは日本人」とまで言う。親としては複雑な思いだ。

もっともそれは自然なことでもある。アメリカの公立幼稚園に通っているので星条旗に向かって胸に手をあて「神のもとに一つとなった自由と正義の民として、アメリカ合衆国の国旗に忠誠を誓います」といった「忠誠の誓い(the Pledge of Allegiance)」を毎朝行っているのだ。さまざまな人種、宗教、価値観が異なる人々をひとつの国家とするには必要なことなのだろう。

しかし彼は日本人の子孫であり、それは一生変わらないのだ。彼が成長するに従い、自分の祖先について考えるようになるだろう。太平洋戦争の歴史をどのように理解するだろうか。彼に正しい知識として日本の近代史を教え、決して一方からではなく、さまざまな側面からそれらを見て考えることの出来る人間になってくれることを願っている。

正しい知識としての歴史は私が日本で繰り返し教わった自虐史ではない。どの国の歴史にも光と影があり、光の部分を強調し影の部分を隠そうする。日本に限っては逆である。影の部分のみを強調する。そして罪悪感のみを背負っている。私の子供達をそうさせてはならないと感じている。

これは私がアメリカに来て年月を経るに従って感じてきたことである。日本という国は日本人が思っているほど悪くはないのだ。日本人は自国のことを「小さな島国」というが、世界に与え続けている影響という意味では、日本はれっきとした大国なのだ。それは過去の日本人が積み上げてきた努力と実績による結果なのである。そのことを忘れてはならない。

私は右でも左でもない。真実を知りたいのだ。そして子供達にそれを伝えなければならない。