How to convert json array to java Object

Use com.amazonaws.util.json.Jackson
import com.amazonaws.util.json.Jackson;
import java.util.ArrayList;
import lombok.Data;

@Data
class DeviceList {
  private ArrayList<String> devices;
}

DeviceList deviceList = Jackson.fromJsonString(
    "{\"devices\":[\"Mobile\", \"Desktop\"]}", 
    DeviceList.class);

Java Spring Bean constructor how to get call stack, backtrace

Easy wasy to print Java call stack or backtrace:
Implement a function and throw an Exception.
Call the function in the place you want to know its backtrace or callstack
And Catch the Exception then
Call Exception.getStackTrace
class MyService {

    public static void f() throws Exception {
        throw new Exception();
    }

    void forTest() {
        try {
            f();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Via this solution, we can get Bean constructor call stack easily.

[tomcat:launchProperties]       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[tomcat:launchProperties]       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[tomcat:launchProperties]       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[tomcat:launchProperties]       at java.lang.reflect.Method.invoke(Method.java:498)
[tomcat:launchProperties]       at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
[tomcat:launchProperties]       at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588)
[tomcat:launchProperties]       at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1178)
[tomcat:launchProperties]       at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1072)
[tomcat:launchProperties]       at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:511)
[tomcat:launchProperties]       at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:481)
[tomcat:launchProperties]       at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:312)
[tomcat:launchProperties]       at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
[tomcat:launchProperties]       at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:308)
[tomcat:launchProperties]       at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
[tomcat:launchProperties]       at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:208)
[tomcat:launchProperties]       at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1136)
[tomcat:launchProperties]       at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1064)
[tomcat:launchProperties]       at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:583)
[tomcat:launchProperties]       at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
[tomcat:launchProperties]       at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:364)
[tomcat:launchProperties]       at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1269)
[tomcat:launchProperties]       at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:551)
[tomcat:launchProperties]       at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:481)
[tomcat:launchProperties]       at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:312)
[tomcat:launchProperties]       at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
[tomcat:launchProperties]       at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:308)
[tomcat:launchProperties]       at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
[tomcat:launchProperties]       at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761)
[tomcat:launchProperties]       at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
[tomcat:launchProperties]       at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543)
[tomcat:launchProperties]       at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:443)
[tomcat:launchProperties]       at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:325)
[tomcat:launchProperties]       at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:107)
[tomcat:launchProperties]       at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4851)
[tomcat:launchProperties]       at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5314)
[tomcat:launchProperties]       at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
[tomcat:launchProperties]       at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1408)
[tomcat:launchProperties]       at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1398)
[tomcat:launchProperties]       at java.util.concurrent.FutureTask.run(FutureTask.java:266)
[tomcat:launchProperties]       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
[tomcat:launchProperties]       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
[tomcat:launchProperties]       at java.lang.Thread.run(Thread.java:748)

How to use @Mock @InjectMocks

class MyService {
    private UserDao userDao;
}

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.runners.MockitoJUnitRunner;

public class MyServiceTest {

    @InjectMocks
    private MyService myService;

    @Mock
    private UserDao userDao;
    
    @Before
    public void setUp() {
        myService = new MyService();
    }
}

Cannot mock/spy class java.lang.String Mockito cannot mock/spy following: - final classes - anonymous classes - primitive types

org.mockito.exceptions.base.MockitoException:
Cannot mock/spy class java.lang.String
Mockito cannot mock/spy following:
- final classes
- anonymous classes
- primitive types
at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl$1.withBefores(JUnit45AndHigherRunnerImpl.java:27)
at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37)
at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)

In case you have to mock String, perhaps you can add a function only visible for testing via
import com.google.common.annotations.VisibleForTesting;
And in this function, mock the String type's value.
For Example:
class MyService {
    
    private String name = "myservice";

    @VisibleForTesting
    void forTest(String mockName) {
        this.name = mockName;
    }
}

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.runners.MockitoJUnitRunner;

public class MyServiceTest {

    private MyService myService;

    @Before
    public void setUp() {
        myService = new MyService();
        myService.forTest("mockName");
    }
}

How to increase terminal window buffer in IntelliJ

Command + Shift + A or Ctrl + Shift + A
Type registry, click "Registry..."
registry...

Increase the "terminal.buffer.max.lines.count" to 100000 or any number you want, the default is 1000.
terminal.buffer.max.lines.count

make vim like source insight, a effective c/c++ ide

IDE

ide3.gif

setup latest vim

git clone https://github.com/vim/vim.git cd vim/src ./configure --enable-cscope --enable-terminal make sudo make install 

https://www.vim.org/git.php

use universal ctags

git clone https://github.com/universal-ctags/ctags.git cd ctags ./autogen.sh ./configure make sudo make instahttps://www.tamacom.com/global/global-6.6.3.tar.gzll 

setup gnu tags

wget https://www.tamacom.com/global/global-6.6.3.tar.gz tar -xvf global-6.6.3.tar.gz cd global-6.6.3 sh reconf.sh  sudo apt install ncurses-dev ./configure --with-universal-ctags=/usr/local/bin/ctags  make  sudo make install 

https://www.tamacom.com/global/global-6.6.3.tar.gz
http://www.gnu.org/software/global/download.html

install gtags as vim plugin

cp gtags.vim ~/.vim/plugin/ cp gtags-cscope.vim ~/.vim/plugin/ 

config gtags as cscope in ~/.vimrc

" gtags configure " To use the default key/mouse mapping: let GtagsCscope_Auto_Map = 1 " To ignore letter case when searching: let GtagsCscope_Ignore_Case = 1 " To use absolute path name: let GtagsCscope_Absolute_Path = 1 " To deterring interruption: let GtagsCscope_Keep_Alive = 1 " If you hope auto loading: let GtagsCscope_Auto_Load = 1 let GtagsCscope_Quiet = 1 " To use 'vim -t ', ':tag' and '<C-]>' set cscopetag let Gtags_Auto_Map = 1 " output cscope result to quickfix  set cscopequickfix=s-,g-,c-,d-,i-,t-,e-,f-,-a " open quickfix window if needx autocmd QuickFixCmdPost [^l]* nested botright cwindow  :nmap \s :cs find s <C-R>=expand("<cword>")<CR><CR> :nmap \a :cs find a <C-R>=expand("<cword>")<CR><CR> :nmap \d :cs find d <C-R>=expand("<cword>")<CR><CR> :nmap \g :cs find g <C-R>=expand("<cword>")<CR><CR> :nmap \i :cs find i <C-R>=expand("<cword>")<CR><CR> :nmap \c :cs find c <C-R>=expand("<cword>")<CR><CR> :nmap \e :cs find e <C-R>=expand("<cword>")<CR><CR> :nmap \t :cs find t <C-R>=expand("<cword>")<CR><CR> :nmap \f :cs find f <C-R>=expand("<cword>")<CR><CR> 

Usage:

cscope commands: add  : Add a new database             (Usage: add file|dir [pre-path] [flags]) find : Query for a pattern            (Usage: find a|c|d|e|f|g|i|s|t name)        a: Find assignments to this symbol        c: Find functions calling this function        d: Find functions called by this function        e: Find this egrep pattern        f: Find this file        g: Find this definition        i: Find files #including this file        s: Find this C symbol        t: Find this text string help : Show this message              (Usage: help) kill : Kill a connection              (Usage: kill #) reset: Reinit all connections         (Usage: reset) show : Show connections               (Usage: show) 

Normal Key Map:
Press \a means "cs f a $cname"
Press \s means "cs f s $cname"
Press \t means "cs f t $cname"
Press \e means "cs f e $cname"
Press \c means "cs f c $cname"
Press \d means "cs f d $cname"
Press \i means "cs f i $cname"
Press \g means "cs f g $cname"
Press \f means "cs f f $cname"

install taglist

unzip taglist_46.zip  Archive:  taglist_46.zip   inflating: plugin/taglist.vim         inflating: doc/taglist.txt          cp plugin/taglist.vim ~/.vim/plugin/ cp doc/taglist.txt ~/.vim/doc/ 

https://www.vim.org/scripts/script.php?script_id=273

configure taglist vim plugin

"taglist settings let Tlist_Inc_Winwidth=0 let Tlist_Use_Right_Window=1 let Tlist_File_Fold_Auto_Close=1 let Tlist_Exit_OnlyWindow=1 let Tlist_Auto_Open=1 :nmap <F8> :TlistToggle<CR> function! g:TlistFocus()   let save_winnr = winnr()     let winnum = bufwinnr("__Tag_List__")       if winnum == -1         :TlistToggle         let winnum = bufwinnr("__Tag_List__")       endif     if winnum != -1       if save_winnr != winnum         exe winnum . 'wincmd w'       endif   endif endfunction "focus to Tag list window via CTL command command! -nargs=0 -bar CTL call g:TlistFocus()     

Usage: Press F8 to toggle taglist

install vim-airline

git clone https://github.com/vim-airline/vim-airline ~/.vim/pack/dist/start/vim-airline 

https://github.com/vim-airline/vim-airline

install fzf.vim

git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf ~/.fzf/install 

~/.vimrc

" If installed using git set rtp+=~/.fzf 

.vimrc

set nocompatible set backspace=indent,eol,start syntax on syntax enable filetype plugin indent on set autoread set showmatch set hlsearch set incsearch set ignorecase set smartcase set encoding=utf-8 set termencoding=utf-8 set fileencodings=utf-8,gb2312,gbk,gb18030 set tabstop=4 set shiftwidth=4 set expandtab set softtabstop=4 set autoindent set smartindent set ruler set paste  "gtags settings set cscopetag let GtagsCscope_Auto_Load = 1 let CtagsCscope_Auto_Map = 1 let GtagsCscope_Quiet = 1 set cscopequickfix=s-,g-,d-,c-,t-,e-,f-,i-  "open quickfix window if needed autocmd QuickFixCmdPost [^l]* nested botright cwindow  "key maps for gtags "find : Query for a pattern            (Usage: find a|c|d|e|f|g|i|s|t name) "       a: Find assignments to this symbol "       c: Find functions calling this function "       d: Find functions called by this function "       e: Find this egrep pattern "       f: Find this file "       g: Find this definition "       i: Find files #including this file "       s: Find this C symbol "       t: Find this text string :nmap \a :cs find a <C-R>=expand("<cword>")<CR><CR> :nmap \c :cs find c <C-R>=expand("<cword>")<CR><CR> :nmap \d :cs find d <C-R>=expand("<cword>")<CR><CR> :nmap \e :cs find e <C-R>=expand("<cword>")<CR><CR> :nmap \f :cs find f <C-R>=expand("<cword>")<CR><CR> :nmap \g :cs find g <C-R>=expand("<cword>")<CR><CR> :nmap \i :cs find i <C-R>=expand("<cword>")<CR><CR> :nmap \s :cs find s <C-R>=expand("<cword>")<CR><CR> :nmap \t :cs find t <C-R>=expand("<cword>")<CR><CR>  "taglist settings let Tlist_Inc_Winwidth=0 let Tlist_Use_Right_Window=1 let Tlist_File_Fold_Auto_Close=1 let Tlist_Exit_OnlyWindow=1 let Tlist_Auto_Open=1  :nmap <F8> :TlistToggle<CR> function! g:TlistFocus()   let save_winnr = winnr()   let winnum = bufwinnr("__Tag_List__")   if winnum == -1     :TlistToggle     let winnum = bufwinnr("__Tag_List__")   endif   if winnum != -1       if save_winnr != winnum         exe winnum . 'wincmd w'       endif   endif endfunction "focus to Tag list window via CTL command command! -nargs=0 -bar CTL call g:TlistFocus()  "lightline settings set laststatus=2 if !has('gui_running')   set t_Co=256 endif  "ale settings let g:ale_completion_enabled = 1  "multiple-cursor settings let g:multi_cursor_use_default_mapping=0 let g:multi_cursor_start_word_key      = '<C-n>' let g:multi_cursor_select_all_word_key = '<C-a>' let g:multi_cursor_start_key           = 'g<C-n>' let g:multi_cursor_select_all_key      = 'g<C-a>' let g:multi_cursor_next_key            = '<C-n>' let g:multi_cursor_prev_key            = '<C-N>' let g:multi_cursor_skip_key            = '<C-x>' let g:multi_cursor_quit_key            = '<Esc>'  "tag preview configure autocmd FileType qf nnoremap <silent><buffer> p :PreviewQuickfix<CR> autocmd FileType qf nnoremap <silent><buffer> P :PreviewClose<CR>  "fzf configure set rtp+=~/.fzf  " This is the default extra key bindings let g:fzf_action = {   \ 'ctrl-t': 'tab split',   \ 'ctrl-x': 'split',   \ 'ctrl-v': 'vsplit' }  " Default fzf layout " - down / up / left / right let g:fzf_layout = { 'left': '~100%' }  " Customize fzf colors to match your color scheme let g:fzf_colors = \ { 'fg':      ['fg', 'Normal'],   \ 'bg':      ['bg', 'Normal'],   \ 'hl':      ['fg', 'Comment'],   \ 'fg+':     ['fg', 'CursorLine', 'CursorColumn', 'Normal'],   \ 'bg+':     ['bg', 'CursorLine', 'CursorColumn'],   \ 'hl+':     ['fg', 'Statement'],   \ 'info':    ['fg', 'PreProc'],   \ 'border':  ['fg', 'Ignore'],   \ 'prompt':  ['fg', 'Conditional'],   \ 'pointer': ['fg', 'Exception'],   \ 'marker':  ['fg', 'Keyword'],   \ 'spinner': ['fg', 'Label'],   \ 'header':  ['fg', 'Comment'] }  " Enable per-command history. " CTRL-N and CTRL-P will be automatically bound to next-history and " previous-history instead of down and up. If you don't like the change, " explicitly bind the keys to down and up in your $FZF_DEFAULT_OPTS. let g:fzf_history_dir = '~/.local/share/fzf-history'  " [Buffers] Jump to the existing window if possible let g:fzf_buffers_jump = 1  " [[B]Commits] Customize the options used by 'git log': let g:fzf_commits_log_options = '--graph --color=always --format="%C(auto)%h%d %s %C(black)%C(bold)%cr"'  " [Tags] Command to generate tags file let g:fzf_tags_command = 'gtags'  " [Commands] --expect expression for directly executing the command let g:fzf_commands_expect = 'alt-enter,ctrl-x'  " Mapping selecting mappings nmap <leader><tab> <plug>(fzf-maps-n) xmap <leader><tab> <plug>(fzf-maps-x) omap <leader><tab> <plug>(fzf-maps-o)  " Insert mode completion imap <c-x><c-k> <plug>(fzf-complete-word) imap <c-x><c-f> <plug>(fzf-complete-path) imap <c-x><c-j> <plug>(fzf-complete-file-ag) imap <c-x><c-l> <plug>(fzf-complete-line)  " Advanced customization using autoload functions inoremap <expr> <c-x><c-k> fzf#vim#complete#word({'left': '15%'})  let g:fzf_files_options =   \ '--preview "(coderay {} || less {}) 2> /dev/null | head -'.&lines.'"'  nmap <C-p> :Files<CR> nmap <C-e> :Buffers<CR>  " press s in qf window to open tag in new split window autocmd FileType qf nnoremap <silent><buffer> s <Enter><C-W>s " press v in qf window to open tag in new vertical split window autocmd FileType qf nnoremap <silent><buffer> v <Enter><C-W>v " press t in qf window to open tag in new tab autocmd FileType qf nnoremap <silent><buffer> t <Enter><C-W>T 

Summary

replace .vimrc and .vim with below repo
https://github.com/lengerrong/ervim.git

set up java spring boot "hello world" web application on ubuntu from zero.

install JDK 8

$ sudo apt-get install openjdk-8-jdk

install Gradle

$ curl -s "https://get.sdkman.io" | bash
$ source "$HOME/.sdkman/bin/sdkman-init.sh"
$ sdk install gradle 5.1.1

Spring Initializr

start.spring.io
get your "demo.zip" and unzip it.
choose "Gradle Project",
please remember add "Web" as dependence,
otherwise there will be compile errors.


springboothelloCreate a simple web application
$ cat src/main/java/com/example/demo/HelloController.java
package com.example.demo;

import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;

@RestController
public class HelloController {

    @RequestMapping("/")
    public String index() {
        return "Greetings from Spring Boot!";
    }

}

Run the Application

$ ./gradlew bootRun

Check out the service.

$ curl localhost:8080
Greetings from Spring Boot!

Generate IDE profile

add two plugin in build.gradle
apply plugin "idea" apply plugin "eclipse" 
generate IDE profile for IntelliJ IDEA(ipr)
./gradlew idea
generate IDE profile for Eclipse(.project)
./gradlew eclipse

Refers

Building an Application with Spring Boot

AWS : how to play a video file from s3 bucket in browser

URI

all you have to do is to sign a request like:

https://s3.amazonaws.com/yourbucket/key?
response-content-disposition=inline&
X-Amz-Algorithm=AWS4-HMAC-SHA256&
X-Amz-Credential=AKIAJWWH7EGSUBWE34IQ/20181228/us-east-1/s3/aws4_request&
X-Amz-Date=20181228T074135Z&
X-Amz-Expires=86400&X-Amz-SignedHeaders=host&
X-Amz-Signature=b3143f8442812e176fd61838813a33f53cfd7e198e1c6e68fab5d03d4a642403
 
and set it as src attribue to a video element.

Player component

import React, { Component } from 'react';
import PropTypes from 'prop-types';

const AWS_SERVICE = 's3';
const crypto = require('crypto');

Date.prototype.toYMDString = function() {
    let year = this.getFullYear().toString();
    let month = this.getUTCMonth() + 1;
    if (month < 10)
      month = "0" + month;
    let day = this.getUTCDate();
    if (day < 10)
      day = "0" + day;
    return String(year) + String(month) 
           + String(day);
}

Date.prototype.toTZString = function() {
    let hour = this.getUTCHours();
    if (hour < 10)
      hour = "0" + hour;
    let minute = this.getUTCMinutes();
    if (minute < 10)
      minute = "0" + minute;
    let second = this.getUTCSeconds();
    if (second < 10)
      second = "0" + second;
    return this.toYMDString() + "T"
      + String(hour) + String(minute)
      + String(second) + "Z";
}

class Player extends Component {
  constructor(props) {
    super(props);
  }

  Hmac(key, string) {
      const hmac = crypto.createHmac('sha256', key);
      hmac.end(string);
      return hmac.read();
  }
  
  Signature(date, region, service, toSign) {
    const { aws_secret_key } = this.props;
      let dateKey = this.Hmac('AWS4' + aws_secret_key, date);
      let dateRegionKey = this.Hmac(dateKey, region);
      let dateRegionServiceKey = this.Hmac(dateRegionKey, service);
      let signingKey = this.Hmac(dateRegionServiceKey, 'aws4_request');
      let signature = this.Hmac(signingKey, toSign).toString('hex');
      return signature;
  }
  
  stringToSign(timeStamp, scope, canonicalRequest) {
      var signParts = [];
      signParts.push('AWS4-HMAC-SHA256');
      signParts.push(timeStamp);
      signParts.push(scope);
      signParts.push(crypto.createHash('sha256').update(canonicalRequest).digest(
  'hex'));
      var result = signParts.join('\n');
      console.log('string to sign');
      console.log(result);
      return result;
  };
  
  canonicalRequest(method, uri, queryString, headers, signedHeaders, hashedPayload) {
    var canonicalParts = [];
    canonicalParts.push(method);
    canonicalParts.push(uri);
    canonicalParts.push(queryString);
    canonicalParts.push(headers);
    canonicalParts.push(signedHeaders);
    canonicalParts.push(hashedPayload);
    var result = canonicalParts.join('\n');
    console.log('canonical request');
    console.log(result);
    return result;
  }

  render() {
    const { aws_key, aws_region, bucket, key } = this.props;
    let uri = "/" + bucket + "/" + key;
    let time_stamp = new Date();
    let tz_time_stamp = time_stamp.toTZString();
    let ymd_time_stamp = time_stamp.toYMDString();
    let scope = ymd_time_stamp + "/" + aws_region + "/" + AWS_SERVICE + "/aws4_request";
    let queryString = "X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=" + encodeURIComponent(aws_key + "/" + scope) + "&X-Amz-Date=" + tz_time_stamp + "&X-Amz-Expires=86400&X-Amz-SignedHeaders=host&response-content-disposition=inline";
    let headers = "host:s3.amazonaws.com";
    let signedHeaders = "";
    let hashedPayload = "host\nUNSIGNED-PAYLOAD";
    let request = this.canonicalRequest('GET', uri, queryString, headers, signedHeaders, hashedPayload);
    let signature = this.Signature(ymd_time_stamp, aws_region, AWS_SERVICE, this.stringToSign(tz_time_stamp, scope, request));
    let url = 'https://s3.amazonaws.com' + uri + '?response-content-disposition=inline&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=' + aws_key + "/" + scope + '&X-Amz-Date=' + tz_time_stamp + '&X-Amz-Expires=86400&X-Amz-SignedHeaders=host&X-Amz-Signature=' + signature;
    console.log(url);
    return (
      <video src={url}
        autoPlay playsInline controls
        style={{width:320,height:240}}>
      </video>
    )
  }
}

Player.propTypes = {
  aws_key: PropTypes.string.isRequired,
  aws_secret_key: PropTypes.string.isRequired,
  aws_region: PropTypes.string.isRequired,
  bucket: PropTypes.string.isRequired,
  key: PropTypes.string.isRequired
};

export default Player;

Usage

    return (
        <Player aws_key={aws_key} bucket={bucket} aws_secret_key={aws_secret_key}
          key={key} aws_region={aws_region}>
        </Player>
    );

example

fixed: embedded-redis: Unable to run on macOS Sonoma

Issue you might see below error while trying to run embedded-redis for your testing on your macOS after you upgrade to Sonoma. java.la...