Posts

Showing posts with the label Java

A New Collection of Thoughtful Learning Apps — Now Available on iOS & Android

Image
I’m excited to share a set of mobile apps I’ve recently completed and published on both the Google Play Store and the Apple App Store. These apps are designed with a simple goal in mind: to make meaningful, structured content more accessible, whether you’re studying theology or improving your English vocabulary. 📱 Now Available on Both Platforms All apps are live and available for download: Google Play Developer Page: https://play.google.com/store/apps/dev?id=5835943159853189043 Apple App Store Developer Page: https://apps.apple.com/ca/developer/q-z-l-corp/id1888794100 📖 Theology & Confession Study Apps For those interested in Reformed theology and classical Christian teachings, I’ve developed a series of apps that present foundational texts in a clean, focused reading format: The Belgic Confession Canons of Dort Heidelberg Catechism Westminster Shorter Catechism Each app is designed to provide a distraction-free experience, making it easier to read, reflect, and revisit these im...

ParallelStream vs Virtual Threads in Java 21: What Actually Works for Database Workloads

Image
ParallelStream vs Virtual Threads in Java 21: What Actually Works for Database Workloads Java offers multiple ways to parallelize work, but not all concurrency models are suitable for database-heavy workloads. In modern systems, especially with large batch processing (e.g., 10,000–50,000 IDs), choosing the right model can drastically change performance. This article compares ParallelStream and Virtual Threads (Java 21) using a real-world scenario: batch database queries in Oracle. 🧠 The Problem: Large Batch Database Queries A common backend scenario is fetching data using large ID lists: Example: - 40,000 transaction IDs - Chunked into 1,000 per query - ~40 database queries executed The key question becomes: how do we execute these 40 queries efficiently? ⚙️ Approach 1: ParallelStream IntStream.range(0, batchCount) .parallel() .mapToObj(i -> repository.query(batch)) How it works Uses ForkJoin common pool Thread count ≈ number of CP...

How to Optimize a Slow JPA Query Processing 40K+ IDs (Real Performance Tuning Guide)

Image
How to Optimize a Slow JPA Query Processing 40K+ IDs (Real Performance Tuning Guide) Handling large datasets efficiently is one of the most common challenges in backend engineering. In this post, I’ll walk through how a query processing 40,000+ IDs went from ~24 seconds down to a few seconds using practical optimization techniques. All domain-specific details have been intentionally removed to focus purely on reusable engineering patterns. 📉 The Problem A service fetches data using a JPA query with a large IN clause and joins between tables: SELECT new SomeDto( A.primaryId, A.field1, A.field2, B.field3, C.metric1, C.metric2 ) FROM EntityA A LEFT JOIN A.relatedEntity B LEFT JOIN EntityC C ON C.refId = A.primaryId WHERE A.primaryId IN :ids Even with chunking (~900 IDs per query), total execution time was around 24 seconds . 🚨 Root Causes Unoptimized JOIN conditions Missing database indexes Sequential query execution ORM (JPA) over...

How We Made a Spring Boot Pagination Query 36× Faster (1.8 Minutes → 3 Seconds)

Image
How We Optimized a Spring Boot Pagination Query by 36× (From 1.8 Minutes to 3 Seconds) In high-traffic backend systems, slow database queries are often the hidden bottleneck that quietly kills performance. In our case, a paginated query powering a reporting API was taking 1.8 minutes to respond under load. After optimization, we reduced it to ~3 seconds . 36× faster ~97.2% less execution time ~3500% performance improvement Here’s how we did it — and the key lessons you can apply immediately. 🧱 The Problem: Slow Pagination Query We had a Spring Data JPA query backing a paginated API. It involved multiple filters, joins, and was returning a large dataset. Original issues: Full entity loading Heavy object graph hydration Unnecessary columns fetched Inefficient filtering logic Expensive pagination count The database schema (simplified and anonymized) looked like this: TABLE txn_line ( line_id BIGINT, order_id BIGINT, product_code ...

How to Safely Truncate a String by Byte Length in Java (UTF-8 Solution)

How to Safely Truncate a String by Byte Length in Java (UTF-8 Solution) In Java backend development, it’s common to enforce size limits on strings, such as: Database column byte limits API payload size constraints Logging or message size restrictions A typical approach is: value.substring(0, n); However, this is not safe when dealing with UTF-8 encoding . The Core Problem: Characters ≠ Bytes In UTF-8 encoding: ASCII characters → 1 byte Chinese characters → 3 bytes Emoji → 4 bytes For example: "hello" → 5 bytes "你好" → 6 bytes "😊" → 4 bytes This means: Truncating by character count does NOT guarantee byte size limits --- Does Java Provide a Built-in Solution? No — Java does not provide a direct method to safely truncate a string by byte length. While Java offers low-level APIs such as: CharsetEncoder ByteBuffer String.getBytes() They are not designed for simple, safe truncation and requ...

Java如何安全按字节长度截断String(UTF-8完整解决方案)

Image
Java如何安全按字节长度截断String(UTF-8完整解决方案) 在Java开发中,我们经常需要对字符串进行长度限制,比如: 数据库字段有字节长度限制 接口参数有大小限制 日志或消息需要截断 很多人第一反应是使用: value.substring(0, n) 但这种方式在涉及 UTF-8 编码 时是 不安全的 。 问题本质:字符长度 ≠ 字节长度 在 UTF-8 编码中: 英文字符 → 1 byte 中文字符 → 3 bytes Emoji → 4 bytes 例如: "hello" → 5 bytes "你好" → 6 bytes "😊" → 4 bytes 因此: substring 按字符截断,无法控制字节大小 --- Java 标准库有没有现成方法? 答案是: 没有直接可用的方法 。 虽然 Java 提供了: CharsetEncoder ByteBuffer String.getBytes() 但都需要手动处理,且实现复杂,不适合直接使用。 --- 错误实现方式(常见坑) ❌ 方式1:substring value.substring(0, 50); 问题:可能超过字节限制 ❌ 方式2:直接截断 byte[] new String(bytes, 0, maxBytes, UTF_8); 问题: 可能截断多字节字符 产生乱码(�) --- 正确实现:UTF-8安全按字节截断 public static String truncateUtf8(String value, int maxBytes) { if (value == null) return null; byte[] bytes = value.getBytes(StandardCharsets.UTF_8); if (bytes.length <= maxBytes) return value; int len = maxBytes; // 找到字符起点 int star...

解决数据库“value too long for column”错误:Java中基于字节的UTF-8字符串截断

Image
解决数据库“value too long for column”错误:Java中基于字节的UTF-8字符串截断 如果你在 Java 后端开发中遇到过 “value too long for column” 的数据库错误,那么问题的根本原因可能并不像表面看起来那么简单。 本文将通过一个真实的生产事故,讲清楚 UTF-8 编码 带来的坑,以及为什么 字符串长度不等于字节长度 ,并提供一个 安全按字节截断字符串 的正确实现方式。 生产问题复盘 我们在生产环境遇到如下错误: value too long for column 数据库字段限制: 50 bytes 输入字符串长度: 53 个字符 代码已做处理:截断为 50 个字符 看起来完全没问题,但插入数据库时依然失败。 根本原因:UTF-8 编码 字符数 ≠ 字节数 在 UTF-8 编码中: 英文字符(ASCII)→ 1 字节 中文字符 → 通常 3 字节 Emoji → 4 字节 因此,一个 50 个字符的字符串,很可能超过 50 字节。 错误的实现方式 常见代码如下: if (value.length() > 50) { value = value.substring(0, 50); } 这只能保证字符数,而无法保证字节数。 更严重的是,如果直接按字节截断,还可能: 截断多字节字符 生成非法 UTF-8 字符串 出现乱码或替换字符(�) 正确解决方案:按字节安全截断 正确做法必须满足: 遵守数据库的 字节限制 保证结果是 合法 UTF-8 字符串 不能截断一个字符的一部分 Java 实现(UTF-8安全截断) public static String truncateUtf8(String value, int maxBytes) { if (value == null) return null; byte[] bytes = value.getBytes(StandardCharsets.UTF_8); if (bytes.length <= maxBytes) return valu...

Fix “Value Too Long for Column” Error: UTF-8 String Truncation by Bytes in Java

Image
Fix “Value Too Long for Column” Error: UTF-8 String Truncation by Bytes in Java If you've ever encountered the "value too long for column" database error, especially in a Java backend, the root cause may not be obvious. In this post, we’ll walk through a real production issue caused by UTF-8 encoding , explain why string length is not equal to byte length , and show how to correctly truncate strings by bytes without breaking multibyte characters. The Production Issue We hit a production error during a database insert: value too long for column Database column limit: 50 bytes Input string length: 53 characters Code already truncated to 50 characters At first glance, everything looked correct—but the insert still failed. Root Cause: UTF-8 Encoding The issue comes down to this: 50 characters does NOT equal 50 bytes in UTF-8 In UTF-8 encoding: ASCII characters → 1 byte Chinese characters → 3 bytes Emoji → 4 bytes This mean...

How a JPA save() Call Silently Overwrote My Data (and How to Fix It)

Image
How a JPA save() Call Silently Overwrote My Data (and How to Fix It) I recently encountered a subtle but dangerous issue in a Spring Boot + JPA application. There were no errors, no exceptions, and no failed transactions — yet a database column was silently overwritten with NULL . If you are using Spring Data JPA and updating the same table from multiple endpoints, this is something you should be aware of. The Simplified Scenario We had two REST endpoints updating the same entity, but different fields. The code below is simplified and mangled for illustration. Endpoint A – updates an external reference EntityX entity = repository.findByKey(refId); // update external reference entity.setExternalRef("ABC123"); repository.save(entity); Endpoint B – updates customer email EntityX entity = repository.findByKey(refId); // update email only entity.setEmail("user@example.com"); repository.save(entity); The assumption was that Endpoint B would ...

Android java: How to display phonetic symbol with correct fonts via WebView ?

Image
First, Download lingoes font file Android default fonts can not display phonetic symbol. lingoes.ttf can, please download it. Second, Put lingoes.ttf to assets/font Last, Add "lingoes" font-family in css files under assets @font-face { font-family: 'lingoes'; src:url('file:///android_asset/fonts/lingoes.ttf') format('truetype'); font-weight: normal; font-style: normal; } Use "lingoes" as font-family for the phonetic symbol content Android java : How to load html files in assets via WebView?

Android java : How to load html files in assets via WebView?

Image
The base url for html files under the assets of your app is "file:///android_asset/" WebView wv = new WebView(context); wv.getSettings().setJavaScriptEnabled(true); wv.loadUrl("file:///android_asset/coca/coca_00001_the.html");

Android java : How to copy/move file from assets to absolute path?

private void moveAssets(String assets_file_path, String absolutePath) throws IOException { File wwwFile = new File(absolutePath); if (wwwFile.exists()) return; InputStream is = activity.getAssets().open(assets_file_path); byte[] buffer = new byte[is.available()]; is.read(buffer); is.close(); wwwFile.createNewFile(); FileOutputStream os = new FileOutputStream(wwwFile); os.write(buffer); os.close(); }

Android java: How to orientation activity layout automatically ?

Add ~ android:screenOrientation="fullSensor" ~ to the activity AndroidManifest.xml activity android:name=".MainActivity" android:screenOrientation="fullSensor"

Android how to detect/register language/locale change listener/receiver

The easy way is to register a BroadcastReceiver for Intent.ACTION_LOCALE_CHANGED . Example: change your ViewModel data when language/locale changed. public class QASViewModel extends ViewModel { @SuppressLint ( "StaticFieldLeak" ) private final FragmentActivity activity ; public QASViewModel ( @NonNull FragmentActivity activity ) { this . activity = activity ; setLangReceiver (); } private void setLangReceiver () { final QASViewModel qasViewModel = this ; final BroadcastReceiver langReceiver = new BroadcastReceiver () { @Override public void onReceive ( Context context , Intent intent ) { // do action when language change } }; activity . getApplicationContext (). registerReceiver ( langReceiver , new IntentFilter ( Intent . ACTION_LOCALE_CHANGED )); } }

Android ViewModel with ArgsConstructor via Custom ViewModelFactory

Android ViewModel is very useful. However ViewModel has no args constructor by default. Typical usage of ViewModel looks like: public class UserModel extends ViewModel { } final UserModel viewModel = ViewModelProviders . of ( this ). get ( UserModel . class ); Let's look the definition of ViewModelProviders.of method. /** * Creates a {@link ViewModelProvider}, which retains ViewModels while a scope of given Activity * is alive. More detailed explanation is in {@link ViewModel}. * * It uses the given {@link Factory} to instantiate new ViewModels. * * @param activity an activity, in whose scope ViewModels should be retained * @param factory a {@code Factory} to instantiate new ViewModels * @return a ViewModelProvider instance */ @NonNull @MainThread public static ViewModelProvider of ( @NonNull FragmentActivity activity , @Nullable Factory factory ) { Have you found it? We can pas...

How to convert UTC Date Time String to Java object and compare it ?

Use java.time.Instant ; import java.time.Instant; Instant instantStart = Instant.parse("20200229T12:00:00Z"); Instant instantEnd = Instant.parse("20200329T12:00:00Z"); Instant instantNow = Instant.now(); return instantNow.isAfter(instantStart) && instantNow.isBefore(instantEnd);

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.sprin...

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.JUnit45AndHigher...

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

Image
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. Create 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 pl...