Mug

repository·master·Indexed 19 days ago

https://github.com/google/mug

A lightweight Java 8+ library for string processing and stream utilities with zero dependencies. It includes dot-parse, a fluent parser combinator API for replacing regular expressions and defining recursive grammars, and dot-cel, a parser for the CEL AST that utilizes Java 21 pattern matching and sealed interfaces. The library also provides a secure, immutable email address parser in the com.google.common.labs.email package.

Tokens
26.1K
Snippets
74
Records
115
Agent score
68%

What's inside google-mug

  1. Introduction to SafeSql

    master

    SafeSql is a compile-time checked SQL template library for Java designed to prevent accidental SQL injection while allowing developers to write direct, readable SQL. It uses a {placeholder} syntax to define parameters within a SQL string. These placeholders are automatically handled via JDBC PreparedStatement when executing queries, ensuring that parameter values are safely isolated from the SQL command structure.

    // Construct a SafeSql with a template and two placeholder values {id} and {name}.
    SafeSql sql = SafeSql.of(
        "select id, name, age from users where id = {id} OR name LIKE '%{name}%'",
        userId, userName);
    
    // convenience method to map `ResultSet` to a list of records or Java beans.
    List<User> users = sql.query(dataSource, User.class);
  2. Overview of mu.util: StringFormat and Substring

    master

    The mu.util package provides two complementary libraries for structured string processing in Java:

    • StringFormat: Used for static, compile-time safe template formatting and parsing. It uses named placeholders (e.g., {id}) instead of positional specifiers.
    • Substring: Used for dynamic, runtime composable substring extraction and splitting. It provides a chainable API for slicing strings safely using Optional-based returns.

    Use StringFormat when you have a known structure to parse or format, and Substring when you need to extract ranges or split strings based on dynamic delimiters.

  3. Overview of the com.google.common.labs.email package

    master

    The com.google.common.labs.email package provides a modern, declarative, and secure email address parser and domain model. It is built using compact parser combinators from dot-parse and is designed as a lightweight, thread-safe, and secure alternative to javax.mail.InternetAddress or Apache EmailValidator.

    Key characteristics include:

    • Immutability: EmailAddress is an immutable record, making it inherently thread-safe.
    • Canonicalization: It automatically strips quotes and unescapes characters during parsing. For example, quoted local parts are converted to their canonical form.
    • Security-First Design: It rejects trailing unconsumed input (EOF-enforced) and defensively rejects RFC 2047 encoded words inside the local-part or domain to prevent spoofing attacks.
  4. Use Mug utilities with Guava

    master
    The mug-guava artifact provides a set of utility classes designed to work seamlessly with both Mug and Guava. It includes tools for safe SQL query building, enhanced collection collectors, string case manipulation, generic binary searching, and improved factory methods for immutable collections.
  5. When to use SafeSql

    master

    SafeSql is a library for writing injection-safe SQL templates in Java without using a DSL or XML. You should use SafeSql if you require:

    • Systematically enforced safety: To prevent SQL injection in large-scale environments where developer vigilance is insufficient.
    • Actual SQL syntax: To allow direct copy-pasting of queries between your Java code and database consoles for debugging.
    • Low learning curve: A WYSIWYG approach that avoids learning a complex Domain Specific Language (DSL).
    • Identifier parameterization: The ability to safely parameterize table and column names.
    • Complex query composition: Managing dynamic subqueries and their associated parameters automatically.
    • Compile-time semantic safety: Preventing accidental parameter misuse (e.g., using a name parameter where an ssn is expected) through type-safe parameter handling.
  6. Compare dot-cel performance against cel-java

    master

    The dot-cel parser is benchmarked against Google's official ANTLR-based Java CEL parser (cel-java using dev.cel:cel). Both parsers are functionally compatible as they construct identical ASTs (com.google.api.expr.v1alpha1.ParsedExpr) including source position metadata such as positions, macro_calls, and line_offsets.

    In performance testing, dot-cel consistently demonstrates higher throughput (lower microseconds per operation) across various expression types, including deep field selections, comprehensions, and batch parsing.

    | Benchmark Scenario / Expression | cel-java (ANTLR parser) | dot-cel (dot-parse Parser) | Speedup |
    | :--- | :---: | :---: | :---: |
    | **`deepFieldMessageSelection`** | 3.299 μs | 1.226 μs | **2.69x** |
    | **`smokeTest`** | 2.712 μs | 1.020 μs | **2.66x** |
    | **`anyFieldMessageSelection`** | 2.481 μs | 1.072 μs | **2.31x** |
    | **`simpleMessageContext`** | 4.335 μs | 1.871 μs | **2.32x** |
    | **`mapComprehension`** | 4.570 μs | 2.039 μs | **2.24x** |
    | **`cppSuite`** | 368.501 μs | 167.147 μs | **2.20x** |
    | **`listComprehension`** | 4.337 μs | 2.012 μs | **2.16x** |
    | **`chainedOrs`** | 8.299 μs | 3.917 μs | **2.12x** |
    | **`chainedAnds`** | 7.881 μs | 3.795 μs | **2.08x** |
    | **`messageCreation`** | 14.000 μs | 7.345 μs | **1.91x** |
    | **`longList`** | 793.293 μs | 477.317 μs | **1.66x** |
  7. What is Walker and how does it differ from Guava Traverser?

    master

    Overview

    Walker is a stream-based traversal utility designed for on-demand discovery of trees and graph structures, such as web link graphs or dependency DAGs. Unlike Guava's Traverser which returns an Iterable, Walker returns a Java Stream, allowing you to leverage standard stream operations like .filter(), .limit(), and .map() during traversal.

    Comparison

    FeatureGuava TraverserMug Walker
    Return valueIterableStream
    Pre-order traversalpreOrderTraversal(...)preOrderFrom(...)
    Post-order traversalpostOrderTraversal(...)postOrderFrom(...)
    Breadth-first traversalbreadthFirst(...)breadthFirstFrom(...)
    Binary tree in-orderinBinaryTree(...).inOrderFrom(...)
    Strongly connected componentsstronglyConnectedComponentsFrom(...)
    Cycle detectiondetectCycleFrom(...)
    Topological ordertopologicalOrderFrom(...)
    Shortest path (weighted)ShortestPath.shortestPathsFrom(...)
  8. What is BiStream and why use it?

    master

    A BiStream is a specialized API designed for fluently streaming through Map or Multimap entries. While Java 8's Stream is powerful, it becomes verbose when performing operations specifically on Map entries (like transforming keys or filtering values). BiStream provides a more readable and concise alternative for these common Map-centric patterns, reducing boilerplate code required for transformations and flattening.

    // Standard Java 8 boilerplate for transforming and filtering Map keys
    map.entrySet().stream()
        .map(e -> Map.entry(transform(e.getKey()), e.getValue()))
        .filter(e -> isGood(e.getKey()))
        .collect(toImmutableMap(Map.Entry::getKey, Map.Entry::getValue));
    
    // Equivalent, more readable BiStream code
    BiStream.from(map)
        .mapKeys(this::transform)
        .filterKeys(this::isGood)
        .toMap();
  9. What is the mug-errorprone plugin?

    master
    The mug-errorprone plugin provides compile-time checks for the com.google.mu.util.StringFormat class (in Mug) and the com.google.mu.safesql.SafeSql class. It ensures that string templates used for parsing and formatting are used safely by catching potential errors during compilation rather than at runtime.
  10. Handling left recursion with OperatorTable

    master

    Dot Parse disallows direct left recursion to prevent StackOverflowError. If you attempt to define a parser that calls itself at the start of its own definition, an IllegalStateException will be thrown at parse definition time.

    For legitimate left-associative grammars (like binary operators or postfix operators), you should use the OperatorTable class instead of manual recursion. OperatorTable allows you to define these declaratively using precedence levels, which is cleaner than manually nesting sub-rules.

    If you only have a single left-associative postfix operator, you can use the .withPostfixes() method on a parser.

    // Using OperatorTable for left-associative postfix operators (e.g., field references like foo.bar)
    Parser<Expr> expr = new OperatorTable<Expr>()
        .postfix(string(".").then(identifier), FieldRef::new, 10)
        .build(identifier.map(IdentifierRef::new));
    
    // Using withPostfixes for a single postfix operator
    Parser<Expr> expr = identifier.map(IdentifierRef::new)
        .withPostfixes(string(".").then(identifier), FieldRef::new);