Tales from the jar side: Veo 3 with Java, UberConf, and the usual social media nonsense
It's only a murder of crows if there's probable caws. (rimshot)
Welcome, fellow jarheads, to Tales from the jar side, the Kousen IT newsletter, for the week of July 13–20, 2025. This week gave several talks at UberConf, and prepared for my upcoming recordings.
AI-generated Video with Java
When I speak about programmatic AI tools, I often use a this table:
I need to update the table. For example, OpenAI now recommends its gpt-image-1 model rather than DALL-E 3, though I’m not convinced it’s significantly better. I used it last week when I was preparing my AI-generated opera talk. Also, I like the ElevenLabs model for text-to-speech better than OpenAI, though that’s just a preference.
The big change, however, is that now there is at least one programmatic way to convert text to video. Google has its Veo 3 model (and the slightly older Veo 2), which used to be accessible only through Google’s AI Studio, and even then only if you were on their Max plan, which is a shocking $250/month. Yeah, no, I’m not doing that.
I recently found out, however, that Veo 3 access has been added to their API model. Veo 3 model generates video with integrated audio, which is pretty slick.
If you check out their example scripts on that link, you’ll see code in the usual suspects: Python, JavaScript, and Go. They do, however, include a REST API as well. Here’s their Python sample:
import time
from google import genai
from google.genai import types
client = genai.Client()
operation = client.models.generate_videos(
model="veo-3.0-generate-preview",
prompt="Panning wide shot of a purring kitten sleeping in the sunshine",
config=types.GenerateVideosConfig(
person_generation="allow_all",
aspect_ratio="16:9",
),
)
while not operation.done:
time.sleep(20)
operation = client.operations.get(operation)
for n, generated_video in enumerate(operation.response.generated_videos):
client.files.download(file=generated_video.video)
generated_video.video.save(f"video{n}.mp4")
The basic idea is that you POST a request to the endpoint with your query and it returns an ID. Then you poll that ID, waiting for a property called done
to be true, at which point you can send a GET request to download the video.
See that while
loop that calls sleep
over and over? That’s called busy waiting, and can become a problem because it blocks an operating system thread indefinitely. That’s where Java provides a few alternatives:
ScheduledExecutor
+CompletableFuture
I have two variants that use thread pools efficiently:
Self-Scheduling: Reschedules the next check only after the current one completesFixed-Rate: Checks at regular intervals (e.g., every 5 seconds) regardless of completion
Reactive Streams (Project Reactor)
Uses
Flux.interval()
for time-based polling with built-in back-pressure handling. Perfect for high-concurrency scenarios but adds complexity.Virtual Threads (Java 21+)
The game-changer: Write simple blocking code that scales efficiently. You can literally useThread.sleep()
in a loop without performance penalties:
// Virtual threads make this efficient again:
while (!operation.done()) {
Thread.sleep(Duration.ofSeconds(5));
operation = client.checkStatus(operation.id());
}
All three approaches properly yield CPU control during wait periods, unlike busy waiting which burns cycles checking constantly. Virtual threads offer the best of both worlds—simple blocking code with excellent performance characteristics. Choose virtual threads for simplicity, reactive for complex streaming, or scheduled patterns for broad compatibility.
Arguably, a lot of this complexity isn’t necessary. If all you want is a simple script to generate a single video, the Python approach is fine. But if you were going to support multiple clients generating many videos concurrently, this should be a lot more efficient. I would expect code like this to eventually wind up being used inside Java frameworks, so the calling code is simple but the implementations are powerful.
Generated videos
Now for the examples. Note that Veo 3 video generation isn’t cheap. The service generates 8 seconds of video or less, and charges $0.75 / second of video, for a total of about $6 total per video. Therefore, I didn’t make many.
Here’s a cat playing with a ball of yarn:
Here are two others that use my typical prompt for images, which is a warrior cat flying into battle on the back of a dragon:
and
All the code is in this GitHub repository. It uses two different HTTP clients (Java’s plain HttpClient
API and Spring’s RestClient
API), along with four polling strategies (listed above). The bottom line is that if you have virtual threads available, use them, because the code is much easier and they do the job just fine.
Have fun. I hope to make a video about all this (YouTube, not generated), but I’m not sure when I’ll get to it.
UberConf 2025
This week was UberConf, one of the NFJS “destination events” they hold every year. I gave five talks, though two of them were connected:
My Tier List of Java features added from Java 8 through 24
Upgrade to Modern Java, parts 1 and 2
An AI Opera Generator, which combined as many different AI tools as possible into a single application. I mostly discussed this last week.
Tips and tricks on how to use Claude Code.
While I think the talks went well, I have to admit I’m a bit out of practice. I used to be able to give five talks in two days without a problem. This time I was really tired when they were done.
The Claude Code talk was almost completely full, and included several attendees who asked lots of questions. That was great, but it meant we didn’t get far in the demos I planned to do. Hopefully that was okay with everybody, because I did address all the questions and gave out lots of information.
I have to say that this conference had the feeling of an ending. Now that I have an academic schedule to worry about, it’s not so easy to travel during the semester. I’ve also had one foot out the door of NFJS for several years now anyway, and I get the sense that many of us who have been there a decade or longer are on the way out. I guess we’ll see when next year’s conference rolls around.
An awful AI pun
In the last few weeks, I’ve given multiple talks and training courses on Claude Code, but only this week did I hear this gag:
Q: What do you call a French developer scratched by a bear?
A: Claude
I’m sad I didn’t hear that gag in time to reuse it in my talks, but that’s probably for the best. I might not have survived otherwise.
Social Media
Mornings
It even rhymes, at least enough for before coffee.
Not sure how the cows feel about it
Creepy but true.
I get way too many of these
I get too many notifications, turn off a bunch of them, then they accumulate again. Rinse and repeat.
Yeah, I get that
Being at a conference this week meant I did a lot more walking than usual, but don’t worry, I’ll get over it eventually.
That explains it
Holy onomatopoeia, Batman!
Zardoz
When I was an undergrad, every year in January they had an all-night science fiction film festival. Each year they had a candidate for worst movie of all time. One year they showed Plan 9 from Outer Space, of course. Another year they featured a movie called Just Imagine, made in 1938, about what life would be like in 1978. To make it worse, it was a musical. Shudder. Eventually the whole room was yelling, “Don’t sing!” Not that it helped, of course.
But one year, sure enough, they showed Zardoz, the horrible monstrosity from early in Sean Connery’s career. This image tells it all:
He did that on purpose, and presumably agreed to let it be used for publicity. Wrap this concept around your head — the movie is significantly worse than that picture, hard as that may be to believe. Fortunately, I haven’t seen it since. If you’re dying of curiosity, see either the Wikipedia page or the IMDb page. Either one is more than enough.
You’ve been warned.
Harsh but fair
That’s what she said.
Didn’t I reference this song last week?
Yes, I get it. Both the singer and his partner are awful, and tried to cheat on each other, but wound up matching up. I hope you’re very happy together. Now please get that song out of my head. I want those brain cells back.
Jenny
Hint: read the odometer.
(Has to have been photoshopped, btw. I’ve seen some cars with high mileage, but that’s a lot.)
Maybe that old earworm will drive out the other old earworm. Have a great week, everybody. :)
Last week:
UberConf
Week 1 of Spring in 3 Weeks, on the O’Reilly Learning Platform
This week:
Week 2 of Spring in 3 Weeks, on the O’Reilly Learning Platform
Managing Your Manager, ditto