Guice (pronounced 'juice') is a lightweight dependency injection framework for Java 6 and above, brought to you by Google.

Overview

Guice

Latest release: 5.0.1

Documentation: User Guide, 5.0.1 javadocs, Latest javadocs
Continuous Integration: Build Status
Mailing Lists: User Mailing List
License: Apache 2.0

Put simply, Guice alleviates the need for factories and the use of new in your Java code. Think of Guice's @Inject as the new new. You will still need to write factories in some cases, but your code will not depend directly on them. Your code will be easier to change, unit test and reuse in other contexts.

Guice embraces Java's type safe nature, especially when it comes to features introduced in Java 5 such as generics and annotations. You might think of Guice as filling in missing features for core Java. Ideally, the language itself would provide most of the same features, but until such a language comes along, we have Guice.

Guice helps you design better APIs, and the Guice API itself sets a good example. Guice is not a kitchen sink. We justify each feature with at least three use cases. When in doubt, we leave it out. We build general functionality which enables you to extend Guice rather than adding every feature to the core framework.

Guice aims to make development and debugging easier and faster, not harder and slower. In that vein, Guice steers clear of surprises and magic. You should be able to understand code with or without tools, though tools can make things even easier. When errors do occur, Guice goes the extra mile to generate helpful messages.

For an introduction to Guice and a comparison to new and the factory pattern, see Bob Lee's video presentation. After that, check out our user's guide.

We've been running Guice in mission critical applications since 2006, and now you can, too. We hope you enjoy it as much as we do.

jolt award

Comments
  • Illegal reflective access by com.google.inject.internal.cglib.core.$ReflectUtils$1

    Illegal reflective access by com.google.inject.internal.cglib.core.$ReflectUtils$1

    WARNING: An illegal reflective access operation has occurred WARNING: Illegal reflective access by com.google.inject.internal.cglib.core.$ReflectUtils$1 (guice.jar) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) WARNING: Please consider reporting this to the maintainers of com.google.inject.internal.cglib.core.$ReflectUtils$1 WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations WARNING: All illegal access operations will be denied in a future release

    affecting oracle java9 with maven

    opened by gripedthumbtacks 133
  • Lifecycle support

    Lifecycle support

    From [email protected] on March 14, 2007 09:22:31

    Support for JSR-250 (javax.annotation) would also be very useful for all those people using init() methods and the list.

    The mapping I think is:

    @PostConstruct -> Called right after construction @Resource -> Analogous to @Inject @PreDestroy -> No concept of destruction, is there? @Generated -> Doesn't apply

    Original issue: http://code.google.com/p/google-guice/issues/detail?id=62

    enhancement imported Priority-Medium Component-NewExtension 
    opened by gissuebot 117
  • submit guice to the maven repository

    submit guice to the maven repository

    From gk5885 on March 12, 2007 09:43:32

    guice seems great, and it'd be nice to be able to use it with maven without having to install the jars into the repository manually.  there already seems to be the beginning of a pom in the trunk, so it'd be great if that got completed and the whole thing got put into the maven repository.

    Original issue: http://code.google.com/p/google-guice/issues/detail?id=59

    bug imported Priority-Medium Milestone-Release2.0 
    opened by gissuebot 60
  • Java 8 lambda definitions can break Guice's internal exception handling

    Java 8 lambda definitions can break Guice's internal exception handling

    From abwallis on July 26, 2013 09:10:49

    If a @Provides method contains a lambda definition, and an uncaught exception is thrown by the @Provides method, Guice's internal exception handling (UncaughtExceptionHandler) fails with com.google.inject.internal.util.$ComputationException, hiding the underlying cause of the failure and preventing the display of Guice's informative stack trace. Note that the lambda does not even have to be executed, a user exception can be thrown before the definition of the lambda and will still trigger the failure. Steps to reproduce: 1. Compile and run the attached file.

    Guice version: 3.0 JDK version: 1.8.0-ea-b98

    Attachment: gist    Java8LambdaIssue.java

    Original issue: http://code.google.com/p/google-guice/issues/detail?id=757

    imported 
    opened by gissuebot 52
  • Java 9 (JDK-9) support for guice

    Java 9 (JDK-9) support for guice

    I am evaluating my projects with a pre-release Java 9 SDK. It's using recent guice that fails to inject the dependencies. Guice is trying to alter some classes in java.base module via setAccessible(...) Reflection call. Many other DI frameworks suffer from the same issue.

    Are you currently working on Java 9 support for guice?

    I used Java(TM) SE Runtime Environment (build 9-ea+159) and guice 1.4.1. Build target is Java 1.8.

    Here is the stack trace that occured when DI-ing:

    Exception in thread "Thread-0" java.lang.ExceptionInInitializerError
          at com.google.inject.internal.cglib.reflect.$FastClass$Generator.getProtectionDomain(FastClass.java:73)
          at com.google.inject.internal.cglib.core.$AbstractClassGenerator.create(AbstractClassGenerator.java:206)
          at com.google.inject.internal.cglib.reflect.$FastClass$Generator.create(FastClass.java:65)
          at com.google.inject.internal.BytecodeGen.newFastClassForMember(BytecodeGen.java:252)
          at com.google.inject.internal.BytecodeGen.newFastClassForMember(BytecodeGen.java:203)
          at com.google.inject.internal.ProviderMethod.create(ProviderMethod.java:69)
          at com.google.inject.internal.ProviderMethodsModule.createProviderMethod(ProviderMethodsModule.java:275)
          at com.google.inject.internal.ProviderMethodsModule.getProviderMethods(ProviderMethodsModule.java:144)
          at com.google.inject.internal.ProviderMethodsModule.configure(ProviderMethodsModule.java:123)
          at com.google.inject.spi.Elements$RecordingBinder.install(Elements.java:340)
          at com.google.inject.spi.Elements$RecordingBinder.install(Elements.java:349)
          at com.google.inject.spi.Elements.getElements(Elements.java:110)
          at com.google.inject.internal.InjectorShell$Builder.build(InjectorShell.java:138)
          at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:104)
          at com.google.inject.Guice.createInjector(Guice.java:99)
          at de.client.main.Factory.createInjector(Factory.java:248)
          at de.client.main.Main$1$1.run(Main.java:76)
          at java.base/java.lang.Thread.run(Thread.java:844)
    Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @a42cff
          at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:335)
          at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:278)
          at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:196)
          at java.base/java.lang.reflect.Method.setAccessible(Method.java:190)
          at com.google.inject.internal.cglib.core.$ReflectUtils$1.run(ReflectUtils.java:52)
          at java.base/java.security.AccessController.doPrivileged(Native Method)
          at com.google.inject.internal.cglib.core.$ReflectUtils.<clinit>(ReflectUtils.java:42)
          ... 21 more
    

    I can surpass that issue using the VM args --add-opens java.base/java.lang=ALL-UNNAMED

    opened by felixblaschke 51
  • [Patch] custom annotation based injection points

    [Patch] custom annotation based injection points

    From james.strachan on October 07, 2008 11:13:11

    There are lots of standards and frameworks which define their own custom injection points. Here's a few off the top of my head; I'm sure there's many more out there...

    JSR 250 & EJB3 defines @Resouce for injecting objects from JNDI JPA defines @PersistenceContext for injecting JPA resources usually prebound to a transaction context etc JAX-RS defines a number of them such as @PathParam, @HeaderParam, @Context etc WebBeans defines @In Stripes defines @SpringBean Apache Camel defines @EndpointInject and @Produces

    This patch makes it easy to implement these custom injection points in frameworks as follows; this example supports @Resource from JSR 250

    {{{ @InjectionAnnotation(Resource.class) public class ResourceProviderFactory<T> implements AnnotationProviderFactory<T> {   private final Context context;

      @Inject   public ResourceProviderFactory(Context context) {     this.context = context;   }

      public Provider<T> createProvider(AnnotatedElement member) {     Resource resource = member.getAnnotation(Resource.class);     Objects.nonNull(resource, "@Resource is missing!");     String name = getJndiName(resource, member);     return new Provider<T>() {...}   } }}}}

    Rather than going into a long discussion in this issue, I'll bring it up on the mailing list and post a link here shortly...

    Note that this patch also includes these patches... https://code.google.com/p/google-guice/issues/detail?id=62 https://code.google.com/p/google-guice/issues/detail?id=78 given the amount of code I've changed for these 3 patches its been a bit tricky separating them out into different patches.

    Mostly this patch involves changes to InjectionPoint and InjectorImpl along with the new interface AnnotationProviderFactory and annotation InjectionAnnotation along with a new test case in the jsr250 module called ResourceTest that tests out the injection of @Resource for field and method injection

    Attachment: gist    custom_annotation_injections.patch

    Original issue: http://code.google.com/p/google-guice/issues/detail?id=258

    imported Type-Extension Priority-High 
    opened by gissuebot 48
  • Support OSGi classloading in Guice

    Support OSGi classloading in Guice

    From mcculls on April 20, 2007 05:33:19

    Here's a simple patch that lets you use Guice on OSGi (including method interception)

    For a more detailed example see my local sandpit project: https://scm.ops4j.org/repos/ops4j/laboratory/users/stuart/peaberry it doesn't do a lot at the moment but it does successfully use several Guice features.

    Attachment: gist    GUICE_OSGI.patch

    Original issue: http://code.google.com/p/google-guice/issues/detail?id=94

    enhancement imported Priority-Medium Milestone-Release2.0 
    opened by gissuebot 43
  • GuiceFilter breaks dispatching to jsp if jasper is being used to compile the jsp

    GuiceFilter breaks dispatching to jsp if jasper is being used to compile the jsp

    From brianm%[email protected] on May 12, 2009 18:42:37

    The Jasper JSP compiler uses request.getServletPath() to name the JSP file. When dispatched to a JSP under the filter the servlet path is either empty or /, which leads to an error when generating a class name for the jsp file before it can be compiled.

    This is happening in 2.0- r943

    Original issue: http://code.google.com/p/google-guice/issues/detail?id=372

    imported 
    opened by gissuebot 37
  • BytecodeGen uses system classloader when applying AOP to system types

    BytecodeGen uses system classloader when applying AOP to system types

    From mcculls on March 03, 2009 08:06:15

    We currently assume that classloader bridging is not required for types from the system classpath. For such cases the BytecodeGen.getClassLoader() method just returns the type's classloader, which will be the system classloader.

    While this assumption is correct most of the time, it won't work when an application loads Guice in a non-system classloader and then proceeds to apply AOP to a system type. In this scenario the system classloader won't have access to the internal AOP types, leading to a runtime exception.

    This situation appears to be uncommon, because I've only just come across one example of this very recently. Because fixing this requires changing the algorithm in BytecodeGen (which would then entail re-testing) I would be OK with this being postponed until 2.1 to avoid further slippage of Guice 2.

    Original issue: http://code.google.com/p/google-guice/issues/detail?id=343

    imported Priority-High Milestone-Release2.1 Type-Patch 
    opened by gissuebot 35
  • Provide access to Guice's own internal TypeConverters

    Provide access to Guice's own internal TypeConverters

    From mcculls on October 10, 2009 11:28:36

    Guice lets you provide your own type converters using:

      Binder.convertToTypes(matcher, typeConverter);

    Original issue: http://code.google.com/p/google-guice/issues/detail?id=436

    imported Type-Patch 3.0 
    opened by gissuebot 31
  • Eager loading for any scope

    Eager loading for any scope

    From kevinb9n on February 27, 2007 03:28:48

    Support eager loading generically for any scope.  Rename eagerlyInContainer() to just eagerly().

    Original issue: http://code.google.com/p/google-guice/issues/detail?id=38

    enhancement imported Priority-Medium Component-Core 
    opened by gissuebot 30
  • Spark2.4.7,Guice:4.0: java.lang.ArrayIndexOutOfBoundsException: 67737

    Spark2.4.7,Guice:4.0: java.lang.ArrayIndexOutOfBoundsException: 67737

    com.google.inject.internal.util.$ComputationException: java.lang.ArrayIndexOutOfBoundsException: 67737 at com.google.inject.internal.util.$MapMaker$StrategyImpl.compute(MapMaker.java:553) at com.google.inject.internal.util.$MapMaker$StrategyImpl.compute(MapMaker.java:419) at com.google.inject.internal.util.$CustomConcurrentHashMap$ComputingImpl.get(CustomConcurrentHashMap.java:2041) at com.google.inject.internal.util.$StackTraceElements.forMember(StackTraceElements.java:53) at com.google.inject.internal.Errors.formatSource(Errors.java:690) at com.google.inject.internal.Errors.formatInjectionPoint(Errors.java:720) at com.google.inject.internal.Errors.formatSource(Errors.java:684) at com.google.inject.internal.Errors.format(Errors.java:555) at com.google.inject.ProvisionException.getMessage(ProvisionException.java:59) at java.lang.Throwable.getLocalizedMessage(Throwable.java:392) at java.lang.Throwable.toString(Throwable.java:481) at java.lang.String.valueOf(String.java:2994) at java.io.PrintStream.println(PrintStream.java:821) at java.lang.Throwable$WrappedPrintStream.println(Throwable.java:749) at java.lang.Throwable.printStackTrace(Throwable.java:656) at java.lang.Throwable.printStackTrace(Throwable.java:644) at java.lang.Throwable.printStackTrace(Throwable.java:635) at com.jd.rec.nl.runtime.fullattrspark.FullAttrSparkProduce4.lambda$main$cc225c98$1(FullAttrSparkProduce4.java:272) at org.apache.spark.api.java.JavaRDDLike.$anonfun$foreachPartitionAsync$1(JavaRDDLike.scala:741) at org.apache.spark.api.java.JavaRDDLike.$anonfun$foreachPartitionAsync$1$adapted(JavaRDDLike.scala:741) at org.apache.spark.SparkContext.$anonfun$submitJob$1(SparkContext.scala:2416) at org.apache.spark.scheduler.ResultTask.runTask(ResultTask.scala:90) at org.apache.spark.scheduler.Task.run(Task.scala:129) at org.apache.spark.executor.Executor$TaskRunner.$anonfun$run$3(Executor.scala:478) at org.apache.spark.util.Utils$.tryWithSafeFinally(Utils.scala:1480) at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:481) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Caused by: java.lang.ArrayIndexOutOfBoundsException: 67737 at com.google.inject.internal.asm.$ClassReader.(Unknown Source) at com.google.inject.internal.asm.$ClassReader.(Unknown Source) at com.google.inject.internal.asm.$ClassReader.(Unknown Source) at com.google.inject.internal.util.$LineNumbers.(LineNumbers.java:62) at com.google.inject.internal.util.$StackTraceElements$1.apply(StackTraceElements.java:36) at com.google.inject.internal.util.$StackTraceElements$1.apply(StackTraceElements.java:33) at com.google.inject.internal.util.$MapMaker$StrategyImpl.compute(MapMaker.java:549) ... 28 more

    opened by liuzhuo19940206 0
  • Can I have more than one aspect for a method and if yes how to ensure order of them with Guice AOP

    Can I have more than one aspect for a method and if yes how to ensure order of them with Guice AOP

    I have single method say "updateTransaction". Now I have two aspects , logging and authorization on this method.

    Authorization aspect checks whether logged in user is authorized to update the transaction and logging aspect logs the parameters. I can

    Module Code:

       AuthorizationImpl authorization = new AuthorizationImpl();
        this.requestInjection(authorization);
        bindInterceptor(Matchers.any(), Matchers.annotatedWith(Authorized.class), authorization);
    
        final Logger logger=  new Logger();
        this.requestInjection(logger);
        this.bindInterceptor(Matchers.any(), Matchers.annotatedWith(Logger.class),   logger); 
    

    Method :

       @Authorized
       @Logger
       public boolean updateTransaction(...)
    

    Questions:

    1. It should invoke updateTransaction method only once, even though I have two interceptors, both are calling invocation.proceed
    2. If the authorization aspect does not allow updateTransaction to be called, then even logger aspect should not call it via proceed.
    3. How to ensure the order of those two aspects ?
    opened by sohansoni 0
  • NullPointerException in ServletDefinition:215

    NullPointerException in ServletDefinition:215

    Hi all,

    in com/google/inject/servlet/ServletDefinition.java, Line 215

                  pathInfo = requestUri.substring(getContextPath().length()).replaceAll("[/]{2,}", "/");
    

    a NullPointerException is thrown when getContextPath() returns null. My understanding of the javadoc on javax.servlet.http.HttpServletRequest.getContextPath() is that it should never be null, but it happens.

    In my case I'm running a dropwizard application with the elastic apm agent and graphql-java. The elastic apm java agent calls this method at the end of an apm-transaction, with instrumentation enabled. It seems to work fine for all servlets, except the graphql one. I checked my setup/config multiple times, but cannot detect anything wrong.

    Is there a chance we can introduce a null-check before calling length() on the context path? Can I help with more info?

    Thank you!

    opened by kurtseebauer 1
  • Support for running in Java 19 by upgrading ASM

    Support for running in Java 19 by upgrading ASM

    The bundled ASM 9.2 doesn't support reading Java 19 class file version 63. While class generation works fine, the error reporting functionality throws the following error

    com.google.common.util.concurrent.UncheckedExecutionException: java.lang.IllegalArgumentException: Unsupported class file major version 63
            at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2055)
            at com.google.common.cache.LocalCache.get(LocalCache.java:3966)
            at com.google.common.cache.LocalCache.getOrLoad(LocalCache.java:3989)
            at com.google.common.cache.LocalCache$LocalLoadingCache.get(LocalCache.java:4950)
            at com.google.common.cache.LocalCache$LocalLoadingCache.getUnchecked(LocalCache.java:4956)
            at com.google.inject.internal.util.StackTraceElements.forMember(StackTraceElements.java:67)
            at com.google.inject.internal.SourceFormatter.formatMember(SourceFormatter.java:91)
            at com.google.inject.internal.SourceFormatter.format(SourceFormatter.java:53)
            at com.google.inject.internal.GenericErrorDetail.formatDetail(GenericErrorDetail.java:26)
            at com.google.inject.spi.ErrorDetail.format(ErrorDetail.java:63)
            at com.google.inject.internal.Messages.formatMessages(Messages.java:90)
            at com.google.inject.CreationException.getMessage(CreationException.java:50)
    ....
    Caused by: java.lang.IllegalArgumentException: Unsupported class file major version 63
            at com.google.inject.internal.asm.$ClassReader.<init>(ClassReader.java:199)
            at com.google.inject.internal.asm.$ClassReader.<init>(ClassReader.java:180)
            at com.google.inject.internal.asm.$ClassReader.<init>(ClassReader.java:166)
            at com.google.inject.internal.asm.$ClassReader.<init>(ClassReader.java:287)
            at com.google.inject.internal.util.LineNumbers.<init>(LineNumbers.java:69)
            at com.google.inject.internal.util.StackTraceElements$1.load(StackTraceElements.java:48)
            at com.google.inject.internal.util.StackTraceElements$1.load(StackTraceElements.java:44)
            at com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3533)
            at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2282)
            at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2159)
            at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2049)
            ... 44 more
    
    opened by arlampin 1
Releases(5.1.0)
Owner
Google
Google ❤️ Open Source
Google
Netflix, Inc. 809 Dec 28, 2022
JayWire Dependency Injection

JayWire Dependency Injection A very small and lightweight dependency injection framework for Java 8 without magic. Main features are: 100% pure Java c

VanillaSource 52 Jul 13, 2022
Dynamic Context Dependency Injection

Welcome to the Project Dynamic CDI JDK Informations Actual version is running from JDK8 up to JDK13. The version 1.0.x is based on JDK8. The implement

Sven Ruppert 8 Dec 10, 2019
A fast dependency injector for Android and Java.

Dagger A fast dependency injector for Java and Android. Dagger is a compile-time framework for dependency injection. It uses no reflection or runtime

Google 16.9k Dec 30, 2022
Xposed Injector by Saygus, and project fixed by Spring Musk

Xposed Injector Xposed Injector to mod games externally. Made by Saygus, and project fixed by Spring Musk. Spring Musk requested me to upload his proj

Menu Modder 10 Nov 1, 2022
JavaFX micro-framework that follows MVVM Pattern with Google Guice dependency Injection

ReactiveDeskFX (JavaFX and Google Guice MVVM Pattern micro-framework) JavaFX micro-framework to develop very fast JavaFX components with minimal code

TangoraBox 3 Jan 9, 2022
Yet another Java annotation-based command parsing library, with Dependency Injection inspired by Guice

Commander A universal java command parsing library Building This project uses Gradle. Clone this repository: git clone https://github.com/OctoPvP/Comm

OctoDev 4 Oct 2, 2022
Lightweight dependency injection for Java and Android (JSR-330)

About Feather Feather is an ultra-lightweight dependency injection (JSR-330) library for Java and Android. Dependency injection frameworks are often p

Zsolt Herpai 341 Nov 29, 2022
A light-weight and dynamic dependency injection framework

⚠️ This project is now part of the EE4J initiative. This repository has been archived as all activities are now happening in the corresponding Eclipse

Java EE 105 Dec 23, 2022
Google Mr4c GNU Lesser 3 Google Mr4c MR4C is an implementation framework that allows you to run native code within the Hadoop execution framework. License: GNU Lesser 3, .

Introduction to the MR4C repo About MR4C MR4C is an implementation framework that allows you to run native code within the Hadoop execution framework.

Google 911 Dec 9, 2022
Netflix, Inc. 809 Dec 28, 2022
The real phobos recode. Brought to you by oHareDaBoss himself.

3arthh4ck The real phobos recode. Brought to you by oHareDaBoss himself. released because grin is a big b word. very uncool of what he did. not swag.

oHare 143 Dec 29, 2022
"Some" Utilities you can use for your Java projects "freely"! Files are compiled with Java-8 and above, but mostly Java-11.

✨ Java-SomeUtils ?? "Some" Utilities you can use for your Java projects "freely"! *"Freely"* forcing you to include the license into your program. Fil

JumperBot_ 2 Jan 6, 2023
JayWire Dependency Injection

JayWire Dependency Injection A very small and lightweight dependency injection framework for Java 8 without magic. Main features are: 100% pure Java c

VanillaSource 52 Jul 13, 2022
Spring Kurulumundan Başlayarak, Spring IOC ve Dependency Injection, Hibernate, Maven ve Spring Boot Konularına Giriş Yapıyoruz.

Spring Tutorial for Beginners File Directory Apache Tomcat Apache Tomcat - Eclipse Bağlantısı Spring Paketlerinin İndirilmesi ve Projeye Entegrasyonu

İbrahim Can Erdoğan 11 Apr 11, 2022
Dynamic Context Dependency Injection

Welcome to the Project Dynamic CDI JDK Informations Actual version is running from JDK8 up to JDK13. The version 1.0.x is based on JDK8. The implement

Sven Ruppert 8 Dec 10, 2019
Mystral (pronounced "Mistral") is an efficient library to deal with relational databases quickly.

Mystral An efficient library to deal with relational databases quickly. A little request: read the Javadoc to understand how these elements work in de

null 13 Jan 4, 2023
Build criterion and ecosystem above multi-model databases

ShardingSphere - Building a Criterion and Ecosystem Above Multi-Model Databases Official Website: https://shardingsphere.apache.org/ Stargazers Over T

The Apache Software Foundation 17.8k Jan 9, 2023
A guild plugin for Minecraft Servers that supports 1.13 and above

OasisGuild Description A guild plugin for Minecraft Servers that supports 1.13 and above Languages zh_cn(简体中文) en_us(English) Placeholders %oasisguild

ChiyodaXiaoYi 2 Apr 6, 2022