[{"data":1,"prerenderedAt":4512},["ShallowReactive",2],{"navigation_docs":3,"-sdks-server-java":244,"-sdks-server-java-surround":4507},[4,51,78,229],{"title":5,"icon":6,"modifiedAt":7,"path":8,"stem":9,"children":10,"page":6},"Getting Started",false,"2026-04-30T19:15:33.000Z","\u002Fgetting-started","1.getting-started",[11,16,21,26,31,36,41,46],{"title":12,"path":13,"stem":14,"icon":15},"Quickstart","\u002Fgetting-started\u002Fquickstart","1.getting-started\u002F1.quickstart","i-lucide-fast-forward",{"title":17,"path":18,"stem":19,"icon":20},"Core Concepts","\u002Fgetting-started\u002Fcore-concepts","1.getting-started\u002F2.core-concepts","i-lucide-workflow",{"title":22,"path":23,"stem":24,"icon":25},"Configs Anatomy","\u002Fgetting-started\u002Fconfigs","1.getting-started\u002F3.configs","i-lucide-file-cog",{"title":27,"path":28,"stem":29,"icon":30},"Architecture","\u002Fgetting-started\u002Farchitecture","1.getting-started\u002F4.architecture","i-lucide-layers",{"title":32,"path":33,"stem":34,"icon":35},"JSON Schema Validation","\u002Fgetting-started\u002Fjson-schema-validation","1.getting-started\u002F5.json-schema-validation","i-lucide-braces",{"title":37,"path":38,"stem":39,"icon":40},"Testing Rules","\u002Fgetting-started\u002Ftesting-targeting-rules","1.getting-started\u002F6.testing-targeting-rules","i-lucide-flask-conical",{"title":42,"path":43,"stem":44,"icon":45},"Segments","\u002Fgetting-started\u002Fsegments","1.getting-started\u002F7.segments","i-lucide-squares-intersect",{"title":47,"path":48,"stem":49,"icon":50},"Pricing & Billing","\u002Fgetting-started\u002Fpricing-and-billing","1.getting-started\u002F8.pricing-and-billing","i-lucide-credit-card",{"title":52,"modifiedAt":53,"defaultOpen":54,"path":55,"stem":56,"children":57,"page":6},"Monitoring","2026-09-24T23:33:20.000Z",true,"\u002Fmonitoring","2.monitoring",[58,63,68,73],{"title":59,"path":60,"stem":61,"icon":62},"Activity","\u002Fmonitoring\u002Factivity","2.monitoring\u002F1.activity","i-lucide-activity",{"title":64,"path":65,"stem":66,"icon":67},"Lifecycle","\u002Fmonitoring\u002Flifecycle","2.monitoring\u002F2.lifecycle","i-lucide-recycle",{"title":69,"path":70,"stem":71,"icon":72},"Alerts","\u002Fmonitoring\u002Falerts","2.monitoring\u002F3.alerts","i-lucide-bell",{"title":74,"path":75,"stem":76,"icon":77},"Dynamic Detection","\u002Fmonitoring\u002Fdynamic-detection","2.monitoring\u002F4.dynamic-detection","i-lucide-hat-glasses",{"title":79,"modifiedAt":53,"defaultOpen":54,"path":80,"stem":81,"children":82,"page":6},"SDKs","\u002Fsdks","3.sdks",[83,88,109,134,150,181,224],{"title":84,"path":85,"stem":86,"icon":87},"Available SDKs","\u002Fsdks\u002Favailable-sdks","3.sdks\u002F1.available-sdks","i-lucide-list",{"title":89,"modifiedAt":53,"icon":90,"defaultOpen":6,"path":91,"stem":92,"children":93,"page":6},"Browser SDKs","i-lucide-monitor","\u002Fsdks\u002Fbrowser","3.sdks\u002F2.browser",[94,99,104],{"title":95,"path":96,"stem":97,"icon":98},"Javascript","\u002Fsdks\u002Fbrowser\u002Fjavascript","3.sdks\u002F2.browser\u002F1.javascript","cd-logos-javascript",{"title":100,"path":101,"stem":102,"icon":103},"React","\u002Fsdks\u002Fbrowser\u002Freact","3.sdks\u002F2.browser\u002F2.react","cd-logos-react-light",{"title":105,"path":106,"stem":107,"icon":108},"Vue","\u002Fsdks\u002Fbrowser\u002Fvue","3.sdks\u002F2.browser\u002F3.vue","cd-logos-vue",{"title":110,"modifiedAt":53,"icon":111,"defaultOpen":6,"path":112,"stem":113,"children":114,"page":6},"Mobile SDKs","i-lucide-smartphone","\u002Fsdks\u002Fmobile","3.sdks\u002F3.mobile",[115,119,124,129],{"title":116,"path":117,"stem":118,"icon":103},"React Native","\u002Fsdks\u002Fmobile\u002Freact-native","3.sdks\u002F3.mobile\u002F1.react-native",{"title":120,"path":121,"stem":122,"icon":123},"Flutter","\u002Fsdks\u002Fmobile\u002Fflutter","3.sdks\u002F3.mobile\u002F2.flutter","cd-logos-flutter",{"title":125,"path":126,"stem":127,"icon":128},"Swift","\u002Fsdks\u002Fmobile\u002Fswift","3.sdks\u002F3.mobile\u002F3.swift","cd-logos-swift",{"title":130,"path":131,"stem":132,"icon":133},"Android","\u002Fsdks\u002Fmobile\u002Fandroid","3.sdks\u002F3.mobile\u002F4.android","cd-logos-android",{"title":135,"modifiedAt":53,"icon":136,"defaultOpen":6,"path":137,"stem":138,"children":139,"page":6},"Meta-framework SDKs","i-lucide-monitor-smartphone","\u002Fsdks\u002Fmeta","3.sdks\u002F4.meta",[140,145],{"title":141,"path":142,"stem":143,"icon":144},"Next.js","\u002Fsdks\u002Fmeta\u002Fnextjs","3.sdks\u002F4.meta\u002F1.nextjs","cd-logos-nextjs",{"title":146,"path":147,"stem":148,"icon":149},"Nuxt","\u002Fsdks\u002Fmeta\u002Fnuxt","3.sdks\u002F4.meta\u002F2.nuxt","cd-logos-nuxt",{"title":151,"modifiedAt":53,"icon":152,"defaultOpen":6,"path":153,"stem":154,"children":155,"page":6},"Server SDKs","i-lucide-server","\u002Fsdks\u002Fserver","3.sdks\u002F5.server",[156,161,166,171,176],{"title":157,"path":158,"stem":159,"icon":160},"Node.js","\u002Fsdks\u002Fserver\u002Fnode-js","3.sdks\u002F5.server\u002F1.node-js","cd-logos-nodejs",{"title":162,"path":163,"stem":164,"icon":165},"Python","\u002Fsdks\u002Fserver\u002Fpython","3.sdks\u002F5.server\u002F2.python","cd-logos-python",{"title":167,"path":168,"stem":169,"icon":170},"Java","\u002Fsdks\u002Fserver\u002Fjava","3.sdks\u002F5.server\u002F3.java","cd-logos-java",{"title":172,"path":173,"stem":174,"icon":175},".NET","\u002Fsdks\u002Fserver\u002Fdotnet","3.sdks\u002F5.server\u002F4.dotnet","cd-logos-dotnet",{"title":177,"path":178,"stem":179,"icon":180},"Go","\u002Fsdks\u002Fserver\u002Fgo","3.sdks\u002F5.server\u002F5.go","cd-logos-go",{"title":182,"modifiedAt":53,"icon":183,"defaultOpen":6,"path":184,"stem":185,"children":186,"page":6},"OpenFeature Providers","cd-logos-openfeature","\u002Fsdks\u002Fopenfeature","3.sdks\u002F6.openfeature",[187,192,196,200,204,208,212,216,220],{"title":188,"path":189,"stem":190,"icon":183,"icons":191},"Web","\u002Fsdks\u002Fopenfeature\u002Fweb","3.sdks\u002F6.openfeature\u002F1.web",[183,98],{"title":125,"path":193,"stem":194,"icon":183,"icons":195},"\u002Fsdks\u002Fopenfeature\u002Fswift","3.sdks\u002F6.openfeature\u002F2.swift",[183,128],{"title":130,"path":197,"stem":198,"icon":183,"icons":199},"\u002Fsdks\u002Fopenfeature\u002Fandroid","3.sdks\u002F6.openfeature\u002F3.android",[183,133],{"title":120,"path":201,"stem":202,"icon":183,"icons":203},"\u002Fsdks\u002Fopenfeature\u002Fflutter","3.sdks\u002F6.openfeature\u002F4.flutter",[183,123],{"title":157,"path":205,"stem":206,"icon":183,"icons":207},"\u002Fsdks\u002Fopenfeature\u002Fnode-js","3.sdks\u002F6.openfeature\u002F5.node-js",[183,160],{"title":162,"path":209,"stem":210,"icon":183,"icons":211},"\u002Fsdks\u002Fopenfeature\u002Fpython","3.sdks\u002F6.openfeature\u002F6.python",[183,165],{"title":167,"path":213,"stem":214,"icon":183,"icons":215},"\u002Fsdks\u002Fopenfeature\u002Fjava","3.sdks\u002F6.openfeature\u002F7.java",[183,170],{"title":172,"path":217,"stem":218,"icon":183,"icons":219},"\u002Fsdks\u002Fopenfeature\u002Fdotnet","3.sdks\u002F6.openfeature\u002F8.dotnet",[183,175],{"title":177,"path":221,"stem":222,"icon":183,"icons":223},"\u002Fsdks\u002Fopenfeature\u002Fgo","3.sdks\u002F6.openfeature\u002F9.go",[183,180],{"title":225,"path":226,"stem":227,"icon":228},"Maven Repository","\u002Fsdks\u002Fmaven-repository","3.sdks\u002F7.maven-repository","i-lucide-package",{"title":230,"modifiedAt":53,"defaultOpen":54,"path":231,"stem":232,"children":233,"page":6},"Integrations","\u002Fintegrations","4.integrations",[234,239],{"title":235,"path":236,"stem":237,"icon":238},"Terraform","\u002Fintegrations\u002Fterraform","4.integrations\u002F1.terraform","cd-logos-terraform",{"title":240,"path":241,"stem":242,"icon":243},"MCP","\u002Fintegrations\u002Fmcp","4.integrations\u002F2.mcp","cd-logos-mcp",{"id":245,"title":246,"body":247,"description":4499,"extension":4500,"links":4501,"meta":4502,"navigation":4504,"path":168,"seo":4505,"stem":169,"__hash__":4506},"docs\u002F3.sdks\u002F5.server\u002F3.java.md","Java Server SDK",{"type":248,"value":249,"toc":4471},"minimark",[250,254,259,264,268,276,283,287,307,822,826,840,961,967,971,984,1015,1020,1027,1033,1039,1161,1166,1172,1211,1221,1308,1313,1316,1412,1581,1588,1727,1732,1735,1738,1741,1775,1882,1889,1893,1900,1974,1977,2139,2143,2146,2461,2464,2496,2531,2596,2603,2607,2610,2617,2762,2771,2836,2840,2843,2875,2881,3061,3067,3085,3089,3092,3097,3106,3112,3118,3124,3134,3137,3142,3145,3151,3154,3158,3161,3174,3282,3286,3298,3304,3321,3574,3595,3599,3605,3816,3853,3857,3871,3952,3956,4019,4049,4053,4184,4190,4356,4360,4378,4382,4467],[251,252],"div",{"hidden":54,"dataTitleIcon":253},"java",[255,256],"external-badges",{"package-url":226,"registry":257,"repo":258},"maven","java-sdks\u002Ftree\u002Fmain\u002Fconfigdirector-server-sdk",[260,261,263],"h2",{"id":262},"introduction","Introduction",[265,266,267],"p",{},"The Java Server SDK is a server-side SDK that evaluates configs and their targeting rules. Upon initialization, it retrieves configs and targeting rules from ConfigDirector services. From that point on, it evaluates configs locally for any user context, and receives updates via server sent events (SSE) when configs are updated on the dashboard or via the admin API.",[265,269,270,271,275],{},"The minimum Java version supported is ",[272,273,274],"code",{},"17",".",[265,277,278,279,282],{},"The client is thread safe. Create one instance when your application starts, share it for the lifetime of the process, and ",[272,280,281],{},"close"," it on shutdown. Evaluations read config state the client already holds in memory, so they make no network calls on the request path.",[260,284,286],{"id":285},"installation","Installation",[265,288,289,290,294,295,298,299,302,303,306],{},"The SDK is published to the ",[291,292,293],"a",{"href":226},"ConfigDirector Maven repository",". Add the repository and the dependency to your build. If your Gradle build declares its repositories in ",[272,296,297],{},"settings.gradle.kts"," or ",[272,300,301],{},"settings.gradle",", under ",[272,304,305],{},"dependencyResolutionManagement",", the repository block goes there instead.",[308,309,310,482,609],"code-group",{},[311,312,318],"pre",{"className":313,"code":314,"filename":315,"language":316,"meta":317,"style":317},"language-kotlin shiki shiki-themes material-theme-lighter github-light github-dark","repositories {\n    mavenCentral()\n    exclusiveContent {\n        forRepository {\n            maven {\n                name = \"ConfigDirector\"\n                url = uri(\"https:\u002F\u002Fmaven.configdirector.com\")\n            }\n        }\n        filter {\n            includeGroup(\"com.configdirector\")\n        }\n    }\n}\n\ndependencies {\n    implementation(\"com.configdirector:server-sdk:1.8.1\")\n}\n","build.gradle.kts","kotlin","",[272,319,320,333,342,350,358,366,380,400,406,412,420,433,438,444,450,456,464,477],{"__ignoreMap":317},[321,322,325,329],"span",{"class":323,"line":324},"line",1,[321,326,328],{"class":327},"sGLFI","repositories",[321,330,332],{"class":331},"su5hD"," {\n",[321,334,336,339],{"class":323,"line":335},2,[321,337,338],{"class":327},"    mavenCentral",[321,340,341],{"class":331},"()\n",[321,343,345,348],{"class":323,"line":344},3,[321,346,347],{"class":327},"    exclusiveContent",[321,349,332],{"class":331},[321,351,353,356],{"class":323,"line":352},4,[321,354,355],{"class":327},"        forRepository",[321,357,332],{"class":331},[321,359,361,364],{"class":323,"line":360},5,[321,362,363],{"class":327},"            maven",[321,365,332],{"class":331},[321,367,369,372,376],{"class":323,"line":368},6,[321,370,371],{"class":331},"                name ",[321,373,375],{"class":374},"smGrS","=",[321,377,379],{"class":378},"s_sjI"," \"ConfigDirector\"\n",[321,381,383,386,388,391,394,397],{"class":323,"line":382},7,[321,384,385],{"class":331},"                url ",[321,387,375],{"class":374},[321,389,390],{"class":327}," uri",[321,392,393],{"class":331},"(",[321,395,396],{"class":378},"\"https:\u002F\u002Fmaven.configdirector.com\"",[321,398,399],{"class":331},")\n",[321,401,403],{"class":323,"line":402},8,[321,404,405],{"class":331},"            }\n",[321,407,409],{"class":323,"line":408},9,[321,410,411],{"class":331},"        }\n",[321,413,415,418],{"class":323,"line":414},10,[321,416,417],{"class":327},"        filter",[321,419,332],{"class":331},[321,421,423,426,428,431],{"class":323,"line":422},11,[321,424,425],{"class":327},"            includeGroup",[321,427,393],{"class":331},[321,429,430],{"class":378},"\"com.configdirector\"",[321,432,399],{"class":331},[321,434,436],{"class":323,"line":435},12,[321,437,411],{"class":331},[321,439,441],{"class":323,"line":440},13,[321,442,443],{"class":331},"    }\n",[321,445,447],{"class":323,"line":446},14,[321,448,449],{"class":331},"}\n",[321,451,453],{"class":323,"line":452},15,[321,454,455],{"emptyLinePlaceholder":54},"\n",[321,457,459,462],{"class":323,"line":458},16,[321,460,461],{"class":327},"dependencies",[321,463,332],{"class":331},[321,465,467,470,472,475],{"class":323,"line":466},17,[321,468,469],{"class":327},"    implementation",[321,471,393],{"class":331},[321,473,474],{"class":378},"\"com.configdirector:server-sdk:1.8.1\"",[321,476,399],{"class":331},[321,478,480],{"class":323,"line":479},18,[321,481,449],{"class":331},[311,483,488],{"className":484,"code":485,"filename":486,"language":487,"meta":317,"style":317},"language-groovy shiki shiki-themes material-theme-lighter github-light github-dark","repositories {\n    mavenCentral()\n    exclusiveContent {\n        forRepository {\n            maven {\n                name = 'ConfigDirector'\n                url = 'https:\u002F\u002Fmaven.configdirector.com'\n            }\n        }\n        filter {\n            includeGroup 'com.configdirector'\n        }\n    }\n}\n\ndependencies {\n    implementation 'com.configdirector:server-sdk:1.8.1'\n}\n","build.gradle","groovy",[272,489,490,495,502,507,512,517,533,546,550,554,559,572,576,580,584,588,593,605],{"__ignoreMap":317},[321,491,492],{"class":323,"line":324},[321,493,494],{"class":331},"repositories {\n",[321,496,497,499],{"class":323,"line":335},[321,498,338],{"class":331},[321,500,341],{"class":501},"sP7_E",[321,503,504],{"class":323,"line":344},[321,505,506],{"class":331},"    exclusiveContent {\n",[321,508,509],{"class":323,"line":352},[321,510,511],{"class":331},"        forRepository {\n",[321,513,514],{"class":323,"line":360},[321,515,516],{"class":331},"            maven {\n",[321,518,519,521,523,527,530],{"class":323,"line":368},[321,520,371],{"class":331},[321,522,375],{"class":374},[321,524,526],{"class":525},"sjJ54"," '",[321,528,529],{"class":378},"ConfigDirector",[321,531,532],{"class":525},"'\n",[321,534,535,537,539,541,544],{"class":323,"line":382},[321,536,385],{"class":331},[321,538,375],{"class":374},[321,540,526],{"class":525},[321,542,543],{"class":378},"https:\u002F\u002Fmaven.configdirector.com",[321,545,532],{"class":525},[321,547,548],{"class":323,"line":402},[321,549,405],{"class":331},[321,551,552],{"class":323,"line":408},[321,553,411],{"class":331},[321,555,556],{"class":323,"line":414},[321,557,558],{"class":331},"        filter {\n",[321,560,561,564,567,570],{"class":323,"line":422},[321,562,563],{"class":331},"            includeGroup ",[321,565,566],{"class":525},"'",[321,568,569],{"class":378},"com.configdirector",[321,571,532],{"class":525},[321,573,574],{"class":323,"line":435},[321,575,411],{"class":331},[321,577,578],{"class":323,"line":440},[321,579,443],{"class":331},[321,581,582],{"class":323,"line":446},[321,583,449],{"class":331},[321,585,586],{"class":323,"line":452},[321,587,455],{"emptyLinePlaceholder":54},[321,589,590],{"class":323,"line":458},[321,591,592],{"class":331},"dependencies {\n",[321,594,595,598,600,603],{"class":323,"line":466},[321,596,597],{"class":331},"    implementation ",[321,599,566],{"class":525},[321,601,602],{"class":378},"com.configdirector:server-sdk:1.8.1",[321,604,532],{"class":525},[321,606,607],{"class":323,"line":479},[321,608,449],{"class":331},[311,610,615],{"className":611,"code":612,"filename":613,"language":614,"meta":317,"style":317},"language-xml shiki shiki-themes material-theme-lighter github-light github-dark","\u003Crepositories>\n  \u003Crepository>\n    \u003Cid>configdirector\u003C\u002Fid>\n    \u003Curl>https:\u002F\u002Fmaven.configdirector.com\u003C\u002Furl>\n    \u003Creleases>\u003Cenabled>true\u003C\u002Fenabled>\u003C\u002Freleases>\n    \u003Csnapshots>\u003Cenabled>false\u003C\u002Fenabled>\u003C\u002Fsnapshots>\n  \u003C\u002Frepository>\n\u003C\u002Frepositories>\n\n\u003Cdependency>\n  \u003CgroupId>com.configdirector\u003C\u002FgroupId>\n  \u003CartifactId>server-sdk\u003C\u002FartifactId>\n  \u003Cversion>1.8.1\u003C\u002Fversion>\n\u003C\u002Fdependency>\n","pom.xml","xml",[272,616,617,628,638,659,676,705,731,740,748,752,761,778,796,814],{"__ignoreMap":317},[321,618,619,622,625],{"class":323,"line":324},[321,620,621],{"class":501},"\u003C",[321,623,328],{"class":624},"sQzsp",[321,626,627],{"class":501},">\n",[321,629,630,633,636],{"class":323,"line":335},[321,631,632],{"class":501},"  \u003C",[321,634,635],{"class":624},"repository",[321,637,627],{"class":501},[321,639,640,643,646,649,652,655,657],{"class":323,"line":344},[321,641,642],{"class":501},"    \u003C",[321,644,645],{"class":624},"id",[321,647,648],{"class":501},">",[321,650,651],{"class":331},"configdirector",[321,653,654],{"class":501},"\u003C\u002F",[321,656,645],{"class":624},[321,658,627],{"class":501},[321,660,661,663,666,668,670,672,674],{"class":323,"line":352},[321,662,642],{"class":501},[321,664,665],{"class":624},"url",[321,667,648],{"class":501},[321,669,543],{"class":331},[321,671,654],{"class":501},[321,673,665],{"class":624},[321,675,627],{"class":501},[321,677,678,680,683,686,689,691,694,696,698,701,703],{"class":323,"line":360},[321,679,642],{"class":501},[321,681,682],{"class":624},"releases",[321,684,685],{"class":501},">\u003C",[321,687,688],{"class":624},"enabled",[321,690,648],{"class":501},[321,692,693],{"class":331},"true",[321,695,654],{"class":501},[321,697,688],{"class":624},[321,699,700],{"class":501},">\u003C\u002F",[321,702,682],{"class":624},[321,704,627],{"class":501},[321,706,707,709,712,714,716,718,721,723,725,727,729],{"class":323,"line":368},[321,708,642],{"class":501},[321,710,711],{"class":624},"snapshots",[321,713,685],{"class":501},[321,715,688],{"class":624},[321,717,648],{"class":501},[321,719,720],{"class":331},"false",[321,722,654],{"class":501},[321,724,688],{"class":624},[321,726,700],{"class":501},[321,728,711],{"class":624},[321,730,627],{"class":501},[321,732,733,736,738],{"class":323,"line":382},[321,734,735],{"class":501},"  \u003C\u002F",[321,737,635],{"class":624},[321,739,627],{"class":501},[321,741,742,744,746],{"class":323,"line":402},[321,743,654],{"class":501},[321,745,328],{"class":624},[321,747,627],{"class":501},[321,749,750],{"class":323,"line":408},[321,751,455],{"emptyLinePlaceholder":54},[321,753,754,756,759],{"class":323,"line":414},[321,755,621],{"class":501},[321,757,758],{"class":624},"dependency",[321,760,627],{"class":501},[321,762,763,765,768,770,772,774,776],{"class":323,"line":422},[321,764,632],{"class":501},[321,766,767],{"class":624},"groupId",[321,769,648],{"class":501},[321,771,569],{"class":331},[321,773,654],{"class":501},[321,775,767],{"class":624},[321,777,627],{"class":501},[321,779,780,782,785,787,790,792,794],{"class":323,"line":435},[321,781,632],{"class":501},[321,783,784],{"class":624},"artifactId",[321,786,648],{"class":501},[321,788,789],{"class":331},"server-sdk",[321,791,654],{"class":501},[321,793,784],{"class":624},[321,795,627],{"class":501},[321,797,798,800,803,805,808,810,812],{"class":323,"line":440},[321,799,632],{"class":501},[321,801,802],{"class":624},"version",[321,804,648],{"class":501},[321,806,807],{"class":331},"1.8.1",[321,809,654],{"class":501},[321,811,802],{"class":624},[321,813,627],{"class":501},[321,815,816,818,820],{"class":323,"line":446},[321,817,654],{"class":501},[321,819,758],{"class":624},[321,821,627],{"class":501},[260,823,825],{"id":824},"configure-and-initialize-the-client","Configure and initialize the client",[827,828,829,837],"ol",{},[830,831,832,833,836],"li",{},"Create an instance of the client providing your server SDK key. You can retrieve a server SDK key for each environment under ",[272,834,835],{},"SDK keys"," in the dashboard's navigation panel.",[830,838,839],{},"Initialize the client to initiate its connection lifecycle.",[311,841,845],{"className":842,"code":843,"filename":844,"language":253,"meta":317,"style":317},"language-java shiki shiki-themes material-theme-lighter github-light github-dark","import com.configdirector.ConfigDirector;\nimport com.configdirector.ConfigDirectorClient;\n\n\u002F\u002F IMPORTANT: Do not commit the server SDK key to your source code, it is a secret value.\n\u002F\u002F Building the client makes no network calls.\nConfigDirectorClient client = ConfigDirector.client(\"YOUR-SERVER-SDK-KEY\");\n\n\u002F\u002F Blocks until the client is initialized or it times out.\n\u002F\u002F If initialization times out, the client will continue attempting to\n\u002F\u002F initialize in the background.\nclient.initialize();\n","ConfigDirectorSetup.java",[272,846,847,868,885,889,895,900,930,934,939,944,949],{"__ignoreMap":317},[321,848,849,853,857,859,861,863,865],{"class":323,"line":324},[321,850,852],{"class":851},"sw1J6","import",[321,854,856],{"class":855},"s_bVq"," com",[321,858,275],{"class":501},[321,860,651],{"class":855},[321,862,275],{"class":501},[321,864,529],{"class":855},[321,866,867],{"class":501},";\n",[321,869,870,872,874,876,878,880,883],{"class":323,"line":335},[321,871,852],{"class":851},[321,873,856],{"class":855},[321,875,275],{"class":501},[321,877,651],{"class":855},[321,879,275],{"class":501},[321,881,882],{"class":855},"ConfigDirectorClient",[321,884,867],{"class":501},[321,886,887],{"class":323,"line":344},[321,888,455],{"emptyLinePlaceholder":54},[321,890,891],{"class":323,"line":352},[321,892,894],{"class":893},"sutJx","\u002F\u002F IMPORTANT: Do not commit the server SDK key to your source code, it is a secret value.\n",[321,896,897],{"class":323,"line":360},[321,898,899],{"class":893},"\u002F\u002F Building the client makes no network calls.\n",[321,901,902,904,907,909,912,914,917,919,922,925,927],{"class":323,"line":368},[321,903,882],{"class":855},[321,905,906],{"class":331}," client ",[321,908,375],{"class":374},[321,910,911],{"class":331}," ConfigDirector",[321,913,275],{"class":501},[321,915,916],{"class":327},"client",[321,918,393],{"class":501},[321,920,921],{"class":525},"\"",[321,923,924],{"class":378},"YOUR-SERVER-SDK-KEY",[321,926,921],{"class":525},[321,928,929],{"class":501},");\n",[321,931,932],{"class":323,"line":382},[321,933,455],{"emptyLinePlaceholder":54},[321,935,936],{"class":323,"line":402},[321,937,938],{"class":893},"\u002F\u002F Blocks until the client is initialized or it times out.\n",[321,940,941],{"class":323,"line":408},[321,942,943],{"class":893},"\u002F\u002F If initialization times out, the client will continue attempting to\n",[321,945,946],{"class":323,"line":414},[321,947,948],{"class":893},"\u002F\u002F initialize in the background.\n",[321,950,951,953,955,958],{"class":323,"line":422},[321,952,916],{"class":331},[321,954,275],{"class":501},[321,956,957],{"class":327},"initialize",[321,959,960],{"class":501},"();\n",[265,962,963,964,966],{},"The client is thread safe. Create one at startup, share it for the lifetime of the process, and call ",[272,965,281],{}," on shutdown.",[968,969,970],"warning",{},"Server SDK keys are secret values. Do not commit them to your source code repository. Provide them at runtime via environment variables instead.",[265,972,973,975,976,979,980,983],{},[272,974,957],{}," blocks until the initial config state arrives or the configured timeout elapses, and it never throws on a connection failure. Check ",[272,977,978],{},"isReady"," to find out whether config state actually arrived. An overload accepts a ",[272,981,982],{},"Duration"," to override the configured timeout for that call:",[311,985,987],{"className":842,"code":986,"filename":844,"language":253,"meta":317,"style":317},"client.initialize(Duration.ofSeconds(5));\n",[272,988,989],{"__ignoreMap":317},[321,990,991,993,995,997,999,1001,1003,1006,1008,1012],{"class":323,"line":324},[321,992,916],{"class":331},[321,994,275],{"class":501},[321,996,957],{"class":327},[321,998,393],{"class":501},[321,1000,982],{"class":331},[321,1002,275],{"class":501},[321,1004,1005],{"class":327},"ofSeconds",[321,1007,393],{"class":501},[321,1009,1011],{"class":1010},"srdBf","5",[321,1013,1014],{"class":501},"));\n",[1016,1017,1019],"h3",{"id":1018},"additional-configuration-options","Additional configuration options",[265,1021,1022,1023,1026],{},"Options are adjusted through the lambda passed to ",[272,1024,1025],{},"ConfigDirector.client",". Every setter returns the options object, so calls chain. They are read once when the client is built; changing them afterwards has no effect.",[1028,1029,1031],"h4",{"id":1030},"metadata",[272,1032,1030],{},[265,1034,1035,1036,1038],{},"The ",[272,1037,1030],{}," option allows you to provide your application's name and version. These values can be used in targeting rules conditionals. For example, if a certain feature should only be enabled starting with a certain version of your application.",[311,1040,1042],{"className":842,"code":1041,"filename":844,"language":253,"meta":317,"style":317},"import com.configdirector.ConfigDirector;\nimport com.configdirector.ConfigDirectorClient;\n\nConfigDirectorClient client = ConfigDirector.client(\n    \"YOUR-SERVER-SDK-KEY\",\n    options -> options.metadata(\"YOUR-APP-NAME\", \"1.0.2\"));\n\nclient.initialize();\n",[272,1043,1044,1060,1076,1080,1097,1109,1147,1151],{"__ignoreMap":317},[321,1045,1046,1048,1050,1052,1054,1056,1058],{"class":323,"line":324},[321,1047,852],{"class":851},[321,1049,856],{"class":855},[321,1051,275],{"class":501},[321,1053,651],{"class":855},[321,1055,275],{"class":501},[321,1057,529],{"class":855},[321,1059,867],{"class":501},[321,1061,1062,1064,1066,1068,1070,1072,1074],{"class":323,"line":335},[321,1063,852],{"class":851},[321,1065,856],{"class":855},[321,1067,275],{"class":501},[321,1069,651],{"class":855},[321,1071,275],{"class":501},[321,1073,882],{"class":855},[321,1075,867],{"class":501},[321,1077,1078],{"class":323,"line":344},[321,1079,455],{"emptyLinePlaceholder":54},[321,1081,1082,1084,1086,1088,1090,1092,1094],{"class":323,"line":352},[321,1083,882],{"class":855},[321,1085,906],{"class":331},[321,1087,375],{"class":374},[321,1089,911],{"class":331},[321,1091,275],{"class":501},[321,1093,916],{"class":327},[321,1095,1096],{"class":501},"(\n",[321,1098,1099,1102,1104,1106],{"class":323,"line":360},[321,1100,1101],{"class":525},"    \"",[321,1103,924],{"class":378},[321,1105,921],{"class":525},[321,1107,1108],{"class":501},",\n",[321,1110,1111,1114,1118,1121,1123,1125,1127,1129,1132,1134,1137,1140,1143,1145],{"class":323,"line":368},[321,1112,1113],{"class":331},"    options ",[321,1115,1117],{"class":1116},"sbsja","->",[321,1119,1120],{"class":331}," options",[321,1122,275],{"class":501},[321,1124,1030],{"class":327},[321,1126,393],{"class":501},[321,1128,921],{"class":525},[321,1130,1131],{"class":378},"YOUR-APP-NAME",[321,1133,921],{"class":525},[321,1135,1136],{"class":501},",",[321,1138,1139],{"class":525}," \"",[321,1141,1142],{"class":378},"1.0.2",[321,1144,921],{"class":525},[321,1146,1014],{"class":501},[321,1148,1149],{"class":323,"line":382},[321,1150,455],{"emptyLinePlaceholder":54},[321,1152,1153,1155,1157,1159],{"class":323,"line":402},[321,1154,916],{"class":331},[321,1156,275],{"class":501},[321,1158,957],{"class":327},[321,1160,960],{"class":501},[1028,1162,1164],{"id":1163},"logger",[272,1165,1163],{},[265,1167,1168,1169,1171],{},"The SDK logs through SLF4J. Left to itself it writes to the logger named ",[272,1170,569],{},", so logging levels, formatting, and destinations can be controlled through your usual SLF4J configuration:",[311,1173,1176],{"className":611,"code":1174,"filename":1175,"language":614,"meta":317,"style":317},"\u003Clogger name=\"com.configdirector\" level=\"DEBUG\" \u002F>\n","logback.xml",[272,1177,1178],{"__ignoreMap":317},[321,1179,1180,1182,1184,1188,1190,1192,1194,1196,1199,1201,1203,1206,1208],{"class":323,"line":324},[321,1181,621],{"class":501},[321,1183,1163],{"class":624},[321,1185,1187],{"class":1186},"s9AJx"," name",[321,1189,375],{"class":501},[321,1191,921],{"class":525},[321,1193,569],{"class":378},[321,1195,921],{"class":525},[321,1197,1198],{"class":1186}," level",[321,1200,375],{"class":501},[321,1202,921],{"class":525},[321,1204,1205],{"class":378},"DEBUG",[321,1207,921],{"class":525},[321,1209,1210],{"class":501}," \u002F>\n",[265,1212,1213,1214,1217,1218,1220],{},"Alternatively, pass any SLF4J ",[272,1215,1216],{},"Logger"," to the ",[272,1219,1163],{}," option to put the SDK's output under your application's own logging namespace, where existing appenders and level configuration already apply:",[311,1222,1224],{"className":842,"code":1223,"filename":844,"language":253,"meta":317,"style":317},"import org.slf4j.LoggerFactory;\n\nConfigDirectorClient client = ConfigDirector.client(\n    \"YOUR-SERVER-SDK-KEY\",\n    options -> options.logger(LoggerFactory.getLogger(\"my-app.configdirector\")));\n",[272,1225,1226,1245,1249,1265,1275],{"__ignoreMap":317},[321,1227,1228,1230,1233,1235,1238,1240,1243],{"class":323,"line":324},[321,1229,852],{"class":851},[321,1231,1232],{"class":855}," org",[321,1234,275],{"class":501},[321,1236,1237],{"class":855},"slf4j",[321,1239,275],{"class":501},[321,1241,1242],{"class":855},"LoggerFactory",[321,1244,867],{"class":501},[321,1246,1247],{"class":323,"line":335},[321,1248,455],{"emptyLinePlaceholder":54},[321,1250,1251,1253,1255,1257,1259,1261,1263],{"class":323,"line":344},[321,1252,882],{"class":855},[321,1254,906],{"class":331},[321,1256,375],{"class":374},[321,1258,911],{"class":331},[321,1260,275],{"class":501},[321,1262,916],{"class":327},[321,1264,1096],{"class":501},[321,1266,1267,1269,1271,1273],{"class":323,"line":352},[321,1268,1101],{"class":525},[321,1270,924],{"class":378},[321,1272,921],{"class":525},[321,1274,1108],{"class":501},[321,1276,1277,1279,1281,1283,1285,1287,1289,1291,1293,1296,1298,1300,1303,1305],{"class":323,"line":360},[321,1278,1113],{"class":331},[321,1280,1117],{"class":1116},[321,1282,1120],{"class":331},[321,1284,275],{"class":501},[321,1286,1163],{"class":327},[321,1288,393],{"class":501},[321,1290,1242],{"class":331},[321,1292,275],{"class":501},[321,1294,1295],{"class":327},"getLogger",[321,1297,393],{"class":501},[321,1299,921],{"class":525},[321,1301,1302],{"class":378},"my-app.configdirector",[321,1304,921],{"class":525},[321,1306,1307],{"class":501},")));\n",[1028,1309,1311],{"id":1310},"connection",[272,1312,1310],{},[265,1314,1315],{},"The connection option accepts a lambda receiving a builder with the following optional values:",[1317,1318,1319,1349,1378,1400],"ul",{},[830,1320,1321,1324],{},[272,1322,1323],{},"mode",[1317,1325,1326,1344],{},[830,1327,1328,1329,298,1332,1335,1336,1339,1340,1343],{},"The connection mode, which can be ",[272,1330,1331],{},"ConnectionMode.STREAMING",[272,1333,1334],{},"ConnectionMode.POLLING",". It is recommended to use the default of ",[272,1337,1338],{},"STREAMING"," unless you have a specific need to use ",[272,1341,1342],{},"POLLING"," instead.",[830,1345,1346,1347],{},"Defaults to ",[272,1348,1331],{},[830,1350,1351,1354],{},[272,1352,1353],{},"pollingInterval",[1317,1355,1356,1373],{},[830,1357,1358,1359,1361,1362,1365,1366,1368,1369,275],{},"Only used in ",[272,1360,1342],{}," mode. The interval to poll ConfigDirector services for updates. A value below the minimum of ",[272,1363,1364],{},"60"," seconds is raised to ",[272,1367,1364],{}," seconds and a warning is logged. See ",[291,1370,1372],{"href":1371},"\u002Fgetting-started\u002Farchitecture#polling-intervals","Polling intervals",[830,1374,1346,1375,1377],{},[272,1376,1011],{}," minutes",[830,1379,1380,1383],{},[272,1381,1382],{},"timeout",[1317,1384,1385,1394],{},[830,1386,1387,1388,1390,1391,1393],{},"The timeout to be used in initialization. This is how long the ",[272,1389,957],{}," method will wait for data from ConfigDirector services. If the timeout is reached, ",[272,1392,957],{}," will return but the client will still be in an unready status and returning default values. While streaming, the client will continue to attempt to connect and retrieve config values in the background.",[830,1395,1346,1396,1399],{},[272,1397,1398],{},"3"," seconds",[830,1401,1402,1404],{},[272,1403,665],{},[1317,1405,1406,1409],{},[830,1407,1408],{},"The base URL used to connect to ConfigDirector services",[830,1410,1411],{},"This should only be provided if your environment requires you to configure a proxy server in order to connect to ConfigDirector services",[311,1413,1415],{"className":842,"code":1414,"filename":844,"language":253,"meta":317,"style":317},"import com.configdirector.ConfigDirector;\nimport com.configdirector.ConnectionMode;\nimport java.time.Duration;\n\nConfigDirectorClient client = ConfigDirector.client(\n    \"YOUR-SERVER-SDK-KEY\",\n    options -> options.connection(connection -> connection\n        .mode(ConnectionMode.POLLING)\n        .pollingInterval(Duration.ofMinutes(10))\n        .timeout(Duration.ofSeconds(5))));\n",[272,1416,1417,1433,1450,1468,1472,1488,1498,1520,1537,1560],{"__ignoreMap":317},[321,1418,1419,1421,1423,1425,1427,1429,1431],{"class":323,"line":324},[321,1420,852],{"class":851},[321,1422,856],{"class":855},[321,1424,275],{"class":501},[321,1426,651],{"class":855},[321,1428,275],{"class":501},[321,1430,529],{"class":855},[321,1432,867],{"class":501},[321,1434,1435,1437,1439,1441,1443,1445,1448],{"class":323,"line":335},[321,1436,852],{"class":851},[321,1438,856],{"class":855},[321,1440,275],{"class":501},[321,1442,651],{"class":855},[321,1444,275],{"class":501},[321,1446,1447],{"class":855},"ConnectionMode",[321,1449,867],{"class":501},[321,1451,1452,1454,1457,1459,1462,1464,1466],{"class":323,"line":344},[321,1453,852],{"class":851},[321,1455,1456],{"class":855}," java",[321,1458,275],{"class":501},[321,1460,1461],{"class":855},"time",[321,1463,275],{"class":501},[321,1465,982],{"class":855},[321,1467,867],{"class":501},[321,1469,1470],{"class":323,"line":352},[321,1471,455],{"emptyLinePlaceholder":54},[321,1473,1474,1476,1478,1480,1482,1484,1486],{"class":323,"line":360},[321,1475,882],{"class":855},[321,1477,906],{"class":331},[321,1479,375],{"class":374},[321,1481,911],{"class":331},[321,1483,275],{"class":501},[321,1485,916],{"class":327},[321,1487,1096],{"class":501},[321,1489,1490,1492,1494,1496],{"class":323,"line":368},[321,1491,1101],{"class":525},[321,1493,924],{"class":378},[321,1495,921],{"class":525},[321,1497,1108],{"class":501},[321,1499,1500,1502,1504,1506,1508,1510,1512,1515,1517],{"class":323,"line":382},[321,1501,1113],{"class":331},[321,1503,1117],{"class":1116},[321,1505,1120],{"class":331},[321,1507,275],{"class":501},[321,1509,1310],{"class":327},[321,1511,393],{"class":501},[321,1513,1514],{"class":331},"connection ",[321,1516,1117],{"class":1116},[321,1518,1519],{"class":331}," connection\n",[321,1521,1522,1525,1527,1529,1531,1533,1535],{"class":323,"line":402},[321,1523,1524],{"class":501},"        .",[321,1526,1323],{"class":327},[321,1528,393],{"class":501},[321,1530,1447],{"class":331},[321,1532,275],{"class":501},[321,1534,1342],{"class":331},[321,1536,399],{"class":501},[321,1538,1539,1541,1543,1545,1547,1549,1552,1554,1557],{"class":323,"line":408},[321,1540,1524],{"class":501},[321,1542,1353],{"class":327},[321,1544,393],{"class":501},[321,1546,982],{"class":331},[321,1548,275],{"class":501},[321,1550,1551],{"class":327},"ofMinutes",[321,1553,393],{"class":501},[321,1555,1556],{"class":1010},"10",[321,1558,1559],{"class":501},"))\n",[321,1561,1562,1564,1566,1568,1570,1572,1574,1576,1578],{"class":323,"line":414},[321,1563,1524],{"class":501},[321,1565,1382],{"class":327},[321,1567,393],{"class":501},[321,1569,982],{"class":331},[321,1571,275],{"class":501},[321,1573,1005],{"class":327},[321,1575,393],{"class":501},[321,1577,1011],{"class":1010},[321,1579,1580],{"class":501},"))));\n",[265,1582,1583,1584,1587],{},"Connection settings can also be built once with ",[272,1585,1586],{},"ConnectionOptions.builder()"," and shared by several clients:",[311,1589,1591],{"className":842,"code":1590,"filename":844,"language":253,"meta":317,"style":317},"import com.configdirector.ConnectionOptions;\n\nConnectionOptions connection = ConnectionOptions.builder()\n    .mode(ConnectionMode.POLLING)\n    .pollingInterval(Duration.ofMinutes(10))\n    .build();\n\nConfigDirectorClient client = ConfigDirector.client(\n    \"YOUR-SERVER-SDK-KEY\",\n    options -> options.connection(connection));\n",[272,1592,1593,1610,1614,1633,1650,1670,1679,1683,1699,1709],{"__ignoreMap":317},[321,1594,1595,1597,1599,1601,1603,1605,1608],{"class":323,"line":324},[321,1596,852],{"class":851},[321,1598,856],{"class":855},[321,1600,275],{"class":501},[321,1602,651],{"class":855},[321,1604,275],{"class":501},[321,1606,1607],{"class":855},"ConnectionOptions",[321,1609,867],{"class":501},[321,1611,1612],{"class":323,"line":335},[321,1613,455],{"emptyLinePlaceholder":54},[321,1615,1616,1618,1621,1623,1626,1628,1631],{"class":323,"line":344},[321,1617,1607],{"class":855},[321,1619,1620],{"class":331}," connection ",[321,1622,375],{"class":374},[321,1624,1625],{"class":331}," ConnectionOptions",[321,1627,275],{"class":501},[321,1629,1630],{"class":327},"builder",[321,1632,341],{"class":501},[321,1634,1635,1638,1640,1642,1644,1646,1648],{"class":323,"line":352},[321,1636,1637],{"class":501},"    .",[321,1639,1323],{"class":327},[321,1641,393],{"class":501},[321,1643,1447],{"class":331},[321,1645,275],{"class":501},[321,1647,1342],{"class":331},[321,1649,399],{"class":501},[321,1651,1652,1654,1656,1658,1660,1662,1664,1666,1668],{"class":323,"line":360},[321,1653,1637],{"class":501},[321,1655,1353],{"class":327},[321,1657,393],{"class":501},[321,1659,982],{"class":331},[321,1661,275],{"class":501},[321,1663,1551],{"class":327},[321,1665,393],{"class":501},[321,1667,1556],{"class":1010},[321,1669,1559],{"class":501},[321,1671,1672,1674,1677],{"class":323,"line":368},[321,1673,1637],{"class":501},[321,1675,1676],{"class":327},"build",[321,1678,960],{"class":501},[321,1680,1681],{"class":323,"line":382},[321,1682,455],{"emptyLinePlaceholder":54},[321,1684,1685,1687,1689,1691,1693,1695,1697],{"class":323,"line":402},[321,1686,882],{"class":855},[321,1688,906],{"class":331},[321,1690,375],{"class":374},[321,1692,911],{"class":331},[321,1694,275],{"class":501},[321,1696,916],{"class":327},[321,1698,1096],{"class":501},[321,1700,1701,1703,1705,1707],{"class":323,"line":408},[321,1702,1101],{"class":525},[321,1704,924],{"class":378},[321,1706,921],{"class":525},[321,1708,1108],{"class":501},[321,1710,1711,1713,1715,1717,1719,1721,1723,1725],{"class":323,"line":414},[321,1712,1113],{"class":331},[321,1714,1117],{"class":1116},[321,1716,1120],{"class":331},[321,1718,275],{"class":501},[321,1720,1310],{"class":327},[321,1722,393],{"class":501},[321,1724,1310],{"class":331},[321,1726,1014],{"class":501},[1028,1728,1730],{"id":1729},"telemetry",[272,1731,1729],{},[265,1733,1734],{},"Telemetry tuning. It is unlikely these settings need to be adjusted. However, in cases where your application has a large number of evaluations per second, you can adjust these settings to tune the memory footprint and frequency of telemetry requests.",[265,1736,1737],{},"Keep in mind that ConfigDirector relies on these telemetry events to provide insights and features related to the configs being used.",[265,1739,1740],{},"The telemetry builder accepts the following optional values:",[1317,1742,1743,1759],{},[830,1744,1745,1748],{},[272,1746,1747],{},"eventQueueLimit",[1317,1749,1750,1753,1756],{},[830,1751,1752],{},"The size limit of telemetry event queues. If the size limit is reached before the events are flushed to the network, older events will be dropped.",[830,1754,1755],{},"ConfigDirector keeps a count of dropped events. If the number of dropped events is higher than 50% of the total events, ConfigDirector will issue an alert in the dashboard.",[830,1757,1758],{},"A number between 100 and 100,000. Defaults to 5,000.",[830,1760,1761,1764],{},[272,1762,1763],{},"flushInterval",[1317,1765,1766,1769,1772],{},[830,1767,1768],{},"How often events are flushed and sent over the network.",[830,1770,1771],{},"Decrease this number if your application consistently captures a large number of events in short periods of time in order to reduce memory footprint from a large event queue.",[830,1773,1774],{},"Defaults to 30 seconds.",[311,1776,1778],{"className":842,"code":1777,"filename":844,"language":253,"meta":317,"style":317},"import java.time.Duration;\n\nConfigDirectorClient client = ConfigDirector.client(\n    \"YOUR-SERVER-SDK-KEY\",\n    options -> options.telemetry(telemetry -> telemetry\n        .eventQueueLimit(10_000)\n        .flushInterval(Duration.ofSeconds(15))));\n",[272,1779,1780,1796,1800,1816,1826,1848,1861],{"__ignoreMap":317},[321,1781,1782,1784,1786,1788,1790,1792,1794],{"class":323,"line":324},[321,1783,852],{"class":851},[321,1785,1456],{"class":855},[321,1787,275],{"class":501},[321,1789,1461],{"class":855},[321,1791,275],{"class":501},[321,1793,982],{"class":855},[321,1795,867],{"class":501},[321,1797,1798],{"class":323,"line":335},[321,1799,455],{"emptyLinePlaceholder":54},[321,1801,1802,1804,1806,1808,1810,1812,1814],{"class":323,"line":344},[321,1803,882],{"class":855},[321,1805,906],{"class":331},[321,1807,375],{"class":374},[321,1809,911],{"class":331},[321,1811,275],{"class":501},[321,1813,916],{"class":327},[321,1815,1096],{"class":501},[321,1817,1818,1820,1822,1824],{"class":323,"line":352},[321,1819,1101],{"class":525},[321,1821,924],{"class":378},[321,1823,921],{"class":525},[321,1825,1108],{"class":501},[321,1827,1828,1830,1832,1834,1836,1838,1840,1843,1845],{"class":323,"line":360},[321,1829,1113],{"class":331},[321,1831,1117],{"class":1116},[321,1833,1120],{"class":331},[321,1835,275],{"class":501},[321,1837,1729],{"class":327},[321,1839,393],{"class":501},[321,1841,1842],{"class":331},"telemetry ",[321,1844,1117],{"class":1116},[321,1846,1847],{"class":331}," telemetry\n",[321,1849,1850,1852,1854,1856,1859],{"class":323,"line":368},[321,1851,1524],{"class":501},[321,1853,1747],{"class":327},[321,1855,393],{"class":501},[321,1857,1858],{"class":1010},"10_000",[321,1860,399],{"class":501},[321,1862,1863,1865,1867,1869,1871,1873,1875,1877,1880],{"class":323,"line":382},[321,1864,1524],{"class":501},[321,1866,1763],{"class":327},[321,1868,393],{"class":501},[321,1870,982],{"class":331},[321,1872,275],{"class":501},[321,1874,1005],{"class":327},[321,1876,393],{"class":501},[321,1878,1879],{"class":1010},"15",[321,1881,1580],{"class":501},[265,1883,1884,1885,1888],{},"A value outside the accepted range throws a ",[272,1886,1887],{},"ConfigDirectorValidationException"," when the client is built.",[1016,1890,1892],{"id":1891},"hooks","Hooks",[265,1894,1895,1896,1899],{},"Hooks are events you can subscribe to in order to be notified of some key actions from the client. Each registration method takes a handler and returns a ",[272,1897,1898],{},"Subscription",", which cancels the registration when closed:",[311,1901,1903],{"className":842,"code":1902,"filename":844,"language":253,"meta":317,"style":317},"Subscription subscription = client.onConfigsUpdated(event -> System.out.println(event.keys()));\n\nsubscription.close(); \u002F\u002F Cancels the registration\n",[272,1904,1905,1955,1959],{"__ignoreMap":317},[321,1906,1907,1909,1912,1914,1917,1919,1922,1924,1927,1929,1932,1934,1937,1939,1942,1944,1947,1949,1952],{"class":323,"line":324},[321,1908,1898],{"class":855},[321,1910,1911],{"class":331}," subscription ",[321,1913,375],{"class":374},[321,1915,1916],{"class":331}," client",[321,1918,275],{"class":501},[321,1920,1921],{"class":327},"onConfigsUpdated",[321,1923,393],{"class":501},[321,1925,1926],{"class":331},"event ",[321,1928,1117],{"class":1116},[321,1930,1931],{"class":331}," System",[321,1933,275],{"class":501},[321,1935,1936],{"class":331},"out",[321,1938,275],{"class":501},[321,1940,1941],{"class":327},"println",[321,1943,393],{"class":501},[321,1945,1946],{"class":331},"event",[321,1948,275],{"class":501},[321,1950,1951],{"class":327},"keys",[321,1953,1954],{"class":501},"()));\n",[321,1956,1957],{"class":323,"line":335},[321,1958,455],{"emptyLinePlaceholder":54},[321,1960,1961,1964,1966,1968,1971],{"class":323,"line":344},[321,1962,1963],{"class":331},"subscription",[321,1965,275],{"class":501},[321,1967,281],{"class":327},[321,1969,1970],{"class":501},"();",[321,1972,1973],{"class":893}," \u002F\u002F Cancels the registration\n",[265,1975,1976],{},"The following hooks are available:",[1317,1978,1979,1991,2017],{},[830,1980,1981,1986],{},[272,1982,1985],{"className":1983},[1984],"font-semibold","onClientReady(Consumer\u003CClientReadyEvent>)",[1317,1987,1988],{},[830,1989,1990],{},"Emitted when the client is initialized. When this event is emitted it means the client has received a payload from the ConfigDirector servers and is ready to evaluate configs. It is emitted once, and a handler registered after that point is never called.",[830,1992,1993,1997],{},[272,1994,1996],{"className":1995},[1984],"onConfigsUpdated(Consumer\u003CConfigsUpdatedEvent>)",[1317,1998,1999,2002,2008,2014],{},[830,2000,2001],{},"Emitted when a payload is received from the ConfigDirector servers with config data. It is emitted during initialization when an entire config payload is received. After initialization, it is emitted when updates are pushed from the server (or discovered via polling if that connection mode is used).",[830,2003,2004,2007],{},[272,2005,2006],{},"keys(): List\u003CString>"," - The config keys that were included in the payload from the server, and the keys of configs whose targeting rules use a segment the payload included, sorted.",[830,2009,2010,2013],{},[272,2011,2012],{},"removedKeys(): List\u003CString>"," - The keys of configs the payload removed, sorted. A config is removed when a full payload no longer includes it. Empty when nothing was removed.",[830,2015,2016],{},"Handlers run on the transport thread, so one that blocks delays later updates.",[830,2018,2019,2023],{},[272,2020,2022],{"className":2021},[1984],"onConfigEvaluated(Consumer\u003CConfigEvaluatedEvent>)",[1317,2024,2025,2028,2136],{},[830,2026,2027],{},"Emitted whenever a config is evaluated. This includes calls to the getters and evaluations delivered to watchers.",[830,2029,2030,2033,2034,2037,2038],{},[272,2031,2032],{},"evaluation(): ConfigEvaluation"," - A ",[272,2035,2036],{},"ConfigEvaluation"," record containing the details of the evaluation:\n",[1317,2039,2040,2046,2052,2062,2068,2126],{},[830,2041,2042,2045],{},[272,2043,2044],{},"key(): String"," - The config key that was evaluated",[830,2047,2048,2051],{},[272,2049,2050],{},"value(): Object"," - The value the config evaluated to, in the type the caller's default asked for. It can be the default value provided to the getter or to the watch. For example, if the config was evaluated before the client was initialized.",[830,2053,2054,2057,2058,2061],{},[272,2055,2056],{},"valueId(): String"," - The value ID, which is a stable hash of the value that can be used for analytics or other third parties rather than sending the ",[272,2059,2060],{},"value",". This can be useful for large values, like a JSON config, or to avoid disclosing the values themselves to third parties.",[830,2063,2064,2067],{},[272,2065,2066],{},"isDefault(): boolean"," - Whether or not the evaluation fell back to the default value provided in code.",[830,2069,2070,2073,2074,2077,2078,2081,2082],{},[272,2071,2072],{},"reason(): EvaluationReason"," - The reason for the evaluation resolution. In the case the config successfully evaluated based on server-provided targeting rules, it will be ",[272,2075,2076],{},"FOUND_MATCH",". If the evaluation had to fall back to the default value, the ",[272,2079,2080],{},"reason"," will encode why the fallback was required:\n",[1317,2083,2084,2090,2096,2102,2108,2114,2120],{},[830,2085,2086,2089],{},[272,2087,2088],{},"CLIENT_NOT_READY"," - The evaluation happened before the client finished initialization",[830,2091,2092,2095],{},[272,2093,2094],{},"CONFIG_STATE_MISSING"," - The requested config key was not present in the payload received from the server. This could be due to an incorrect config key, or a config that was not enabled to be available to client SDKs.",[830,2097,2098,2101],{},[272,2099,2100],{},"INVALID_NUMBER"," - The config was requested as a number but the value received from the server could not be converted to a number.",[830,2103,2104,2107],{},[272,2105,2106],{},"INVALID_BOOLEAN"," - The config was requested as a boolean but the value received from the server could not be converted to a boolean.",[830,2109,2110,2113],{},[272,2111,2112],{},"INVALID_JSON"," - The config was requested as JSON but the value received from the server could not be converted to a JSON object or array.",[830,2115,2116,2119],{},[272,2117,2118],{},"TYPE_MISMATCH"," - The config was requested with a data type that did not match the type of the config and no reasonable type conversion was possible.",[830,2121,2122,2125],{},[272,2123,2124],{},"VALUE_MISSING"," - The config key was present in the payload received from the server, but it carried no value.",[830,2127,2128,2131,2132,2135],{},[272,2129,2130],{},"context(): Context"," - The user context that was provided to the evaluation function, or ",[272,2133,2134],{},"null"," if no context was provided.",[830,2137,2138],{},"Handlers run on the calling thread, so one that blocks delays the getter that triggered it.",[260,2140,2142],{"id":2141},"retrieve-config-values","Retrieve config values",[265,2144,2145],{},"Retrieve config values via the typed getters, and subscribe to updates via the matching typed watches. The first argument is the config key and the second is the default value, which is returned if the config is not available or cannot be parsed as the given type:",[311,2147,2150],{"className":842,"code":2148,"filename":2149,"language":253,"meta":317,"style":317},"import com.configdirector.Subscription;\nimport java.util.Map;\n\n\u002F\u002F Retrieve config values\nint retries = client.getInteger(\"max-retries\", 3);\nString theme = client.getString(\"theme\", \"light\");\nboolean newCheckout = client.getBoolean(\"new-checkout\", false);\nMap\u003CString, Object> limits = client.getJsonObject(\"rate-limits\", Map.of(\"per_minute\", 60)); \u002F\u002F JSON config\n\n\u002F\u002F Watch for config updates\nSubscription subscription = client.watchBoolean(\n    \"new-checkout\",\n    false,\n    value -> System.out.println(\"new-checkout is now \" + value));\n\n\u002F\u002F Call close when the subscription is no longer needed\nsubscription.close();\n","Main.java",[272,2151,2152,2168,2186,2190,2195,2228,2265,2299,2365,2369,2374,2391,2401,2408,2442,2446,2451],{"__ignoreMap":317},[321,2153,2154,2156,2158,2160,2162,2164,2166],{"class":323,"line":324},[321,2155,852],{"class":851},[321,2157,856],{"class":855},[321,2159,275],{"class":501},[321,2161,651],{"class":855},[321,2163,275],{"class":501},[321,2165,1898],{"class":855},[321,2167,867],{"class":501},[321,2169,2170,2172,2174,2176,2179,2181,2184],{"class":323,"line":335},[321,2171,852],{"class":851},[321,2173,1456],{"class":855},[321,2175,275],{"class":501},[321,2177,2178],{"class":855},"util",[321,2180,275],{"class":501},[321,2182,2183],{"class":855},"Map",[321,2185,867],{"class":501},[321,2187,2188],{"class":323,"line":344},[321,2189,455],{"emptyLinePlaceholder":54},[321,2191,2192],{"class":323,"line":352},[321,2193,2194],{"class":893},"\u002F\u002F Retrieve config values\n",[321,2196,2197,2200,2203,2205,2207,2209,2212,2214,2216,2219,2221,2223,2226],{"class":323,"line":360},[321,2198,2199],{"class":1116},"int",[321,2201,2202],{"class":331}," retries ",[321,2204,375],{"class":374},[321,2206,1916],{"class":331},[321,2208,275],{"class":501},[321,2210,2211],{"class":327},"getInteger",[321,2213,393],{"class":501},[321,2215,921],{"class":525},[321,2217,2218],{"class":378},"max-retries",[321,2220,921],{"class":525},[321,2222,1136],{"class":501},[321,2224,2225],{"class":1010}," 3",[321,2227,929],{"class":501},[321,2229,2230,2233,2236,2238,2240,2242,2245,2247,2249,2252,2254,2256,2258,2261,2263],{"class":323,"line":368},[321,2231,2232],{"class":855},"String",[321,2234,2235],{"class":331}," theme ",[321,2237,375],{"class":374},[321,2239,1916],{"class":331},[321,2241,275],{"class":501},[321,2243,2244],{"class":327},"getString",[321,2246,393],{"class":501},[321,2248,921],{"class":525},[321,2250,2251],{"class":378},"theme",[321,2253,921],{"class":525},[321,2255,1136],{"class":501},[321,2257,1139],{"class":525},[321,2259,2260],{"class":378},"light",[321,2262,921],{"class":525},[321,2264,929],{"class":501},[321,2266,2267,2270,2273,2275,2277,2279,2282,2284,2286,2289,2291,2293,2297],{"class":323,"line":382},[321,2268,2269],{"class":1116},"boolean",[321,2271,2272],{"class":331}," newCheckout ",[321,2274,375],{"class":374},[321,2276,1916],{"class":331},[321,2278,275],{"class":501},[321,2280,2281],{"class":327},"getBoolean",[321,2283,393],{"class":501},[321,2285,921],{"class":525},[321,2287,2288],{"class":378},"new-checkout",[321,2290,921],{"class":525},[321,2292,1136],{"class":501},[321,2294,2296],{"class":2295},"s39Yj"," false",[321,2298,929],{"class":501},[321,2300,2301,2303,2305,2307,2309,2312,2314,2317,2319,2321,2323,2326,2328,2330,2333,2335,2337,2340,2342,2345,2347,2349,2352,2354,2356,2359,2362],{"class":323,"line":402},[321,2302,2183],{"class":855},[321,2304,621],{"class":501},[321,2306,2232],{"class":1116},[321,2308,1136],{"class":501},[321,2310,2311],{"class":1116}," Object",[321,2313,648],{"class":501},[321,2315,2316],{"class":331}," limits ",[321,2318,375],{"class":374},[321,2320,1916],{"class":331},[321,2322,275],{"class":501},[321,2324,2325],{"class":327},"getJsonObject",[321,2327,393],{"class":501},[321,2329,921],{"class":525},[321,2331,2332],{"class":378},"rate-limits",[321,2334,921],{"class":525},[321,2336,1136],{"class":501},[321,2338,2339],{"class":331}," Map",[321,2341,275],{"class":501},[321,2343,2344],{"class":327},"of",[321,2346,393],{"class":501},[321,2348,921],{"class":525},[321,2350,2351],{"class":378},"per_minute",[321,2353,921],{"class":525},[321,2355,1136],{"class":501},[321,2357,2358],{"class":1010}," 60",[321,2360,2361],{"class":501},"));",[321,2363,2364],{"class":893}," \u002F\u002F JSON config\n",[321,2366,2367],{"class":323,"line":408},[321,2368,455],{"emptyLinePlaceholder":54},[321,2370,2371],{"class":323,"line":414},[321,2372,2373],{"class":893},"\u002F\u002F Watch for config updates\n",[321,2375,2376,2378,2380,2382,2384,2386,2389],{"class":323,"line":422},[321,2377,1898],{"class":855},[321,2379,1911],{"class":331},[321,2381,375],{"class":374},[321,2383,1916],{"class":331},[321,2385,275],{"class":501},[321,2387,2388],{"class":327},"watchBoolean",[321,2390,1096],{"class":501},[321,2392,2393,2395,2397,2399],{"class":323,"line":435},[321,2394,1101],{"class":525},[321,2396,2288],{"class":378},[321,2398,921],{"class":525},[321,2400,1108],{"class":501},[321,2402,2403,2406],{"class":323,"line":440},[321,2404,2405],{"class":2295},"    false",[321,2407,1108],{"class":501},[321,2409,2410,2413,2415,2417,2419,2421,2423,2425,2427,2429,2432,2434,2437,2440],{"class":323,"line":446},[321,2411,2412],{"class":331},"    value ",[321,2414,1117],{"class":1116},[321,2416,1931],{"class":331},[321,2418,275],{"class":501},[321,2420,1936],{"class":331},[321,2422,275],{"class":501},[321,2424,1941],{"class":327},[321,2426,393],{"class":501},[321,2428,921],{"class":525},[321,2430,2431],{"class":378},"new-checkout is now ",[321,2433,921],{"class":525},[321,2435,2436],{"class":374}," +",[321,2438,2439],{"class":331}," value",[321,2441,1014],{"class":501},[321,2443,2444],{"class":323,"line":452},[321,2445,455],{"emptyLinePlaceholder":54},[321,2447,2448],{"class":323,"line":458},[321,2449,2450],{"class":893},"\u002F\u002F Call close when the subscription is no longer needed\n",[321,2452,2453,2455,2457,2459],{"class":323,"line":466},[321,2454,1963],{"class":331},[321,2456,275],{"class":501},[321,2458,281],{"class":327},[321,2460,960],{"class":501},[265,2462,2463],{},"The type a config is parsed as is decided by the getter you call. Each one takes the value to return when the config is missing, the service is unreachable, or the value will not convert to the requested type — so the default should always be the safe choice:",[1317,2465,2466,2471,2476,2481,2486,2491],{},[830,2467,2468],{},[272,2469,2470],{},"getBoolean(String configKey, boolean defaultValue)",[830,2472,2473],{},[272,2474,2475],{},"getString(String configKey, String defaultValue)",[830,2477,2478],{},[272,2479,2480],{},"getInteger(String configKey, int defaultValue)",[830,2482,2483],{},[272,2484,2485],{},"getDouble(String configKey, double defaultValue)",[830,2487,2488],{},[272,2489,2490],{},"getJsonObject(String configKey, Map\u003CString, Object> defaultValue)",[830,2492,2493],{},[272,2494,2495],{},"getJsonArray(String configKey, List\u003CObject> defaultValue)",[265,2497,2498,2499,2502,2503,2505,2506,2509,2510,2509,2512,2509,2515,2509,2518,2509,2521,2509,2524,2526,2527,2530],{},"There is also ",[272,2500,2501],{},"getValue",", the counterpart to ",[272,2504,2501],{}," in the other ConfigDirector SDKs. It takes the type from the default value, which must be a ",[272,2507,2508],{},"Boolean",", ",[272,2511,2232],{},[272,2513,2514],{},"Integer",[272,2516,2517],{},"Long",[272,2519,2520],{},"Double",[272,2522,2523],{},"Float",[272,2525,2183],{},", or ",[272,2528,2529],{},"List",", and must not be null:",[311,2532,2534],{"className":842,"code":2533,"filename":2149,"language":253,"meta":317,"style":317},"boolean newCheckout = client.getValue(\"new-checkout\", false);\nString theme = client.getValue(\"theme\", \"light\");\n",[272,2535,2536,2564],{"__ignoreMap":317},[321,2537,2538,2540,2542,2544,2546,2548,2550,2552,2554,2556,2558,2560,2562],{"class":323,"line":324},[321,2539,2269],{"class":1116},[321,2541,2272],{"class":331},[321,2543,375],{"class":374},[321,2545,1916],{"class":331},[321,2547,275],{"class":501},[321,2549,2501],{"class":327},[321,2551,393],{"class":501},[321,2553,921],{"class":525},[321,2555,2288],{"class":378},[321,2557,921],{"class":525},[321,2559,1136],{"class":501},[321,2561,2296],{"class":2295},[321,2563,929],{"class":501},[321,2565,2566,2568,2570,2572,2574,2576,2578,2580,2582,2584,2586,2588,2590,2592,2594],{"class":323,"line":335},[321,2567,2232],{"class":855},[321,2569,2235],{"class":331},[321,2571,375],{"class":374},[321,2573,1916],{"class":331},[321,2575,275],{"class":501},[321,2577,2501],{"class":327},[321,2579,393],{"class":501},[321,2581,921],{"class":525},[321,2583,2251],{"class":378},[321,2585,921],{"class":525},[321,2587,1136],{"class":501},[321,2589,1139],{"class":525},[321,2591,2260],{"class":378},[321,2593,921],{"class":525},[321,2595,929],{"class":501},[2597,2598,2599,2600,275],"note",{},"Getters never throw when a config is missing or a value will not convert — they return your default instead. Which of those happened is reported through ",[272,2601,2602],{},"onConfigEvaluated",[1016,2604,2606],{"id":2605},"evaluate-config-values-with-a-user-context","Evaluate config values with a user context",[2597,2608,2609],{},"Unlike client SDKs, the server SDKs are able to evaluate targeting rules for the given user context locally without additional network calls.",[265,2611,2612,2613,2616],{},"Every getter has an overload taking a ",[272,2614,2615],{},"Context"," as its last argument, which is what targeting rules are evaluated against. The same key can therefore resolve differently per user:",[311,2618,2620],{"className":842,"code":2619,"filename":2149,"language":253,"meta":317,"style":317},"import com.configdirector.Context;\n\nContext context = Context.builder()\n    .id(\"user-id\")\n    .name(\"Example User\")\n    .trait(\"region\", \"North America\")\n    .build();\n\nclient.getBoolean(\"my-boolean-config-key\", false, context);\n",[272,2621,2622,2638,2642,2660,2677,2695,2722,2730,2734],{"__ignoreMap":317},[321,2623,2624,2626,2628,2630,2632,2634,2636],{"class":323,"line":324},[321,2625,852],{"class":851},[321,2627,856],{"class":855},[321,2629,275],{"class":501},[321,2631,651],{"class":855},[321,2633,275],{"class":501},[321,2635,2615],{"class":855},[321,2637,867],{"class":501},[321,2639,2640],{"class":323,"line":335},[321,2641,455],{"emptyLinePlaceholder":54},[321,2643,2644,2646,2649,2651,2654,2656,2658],{"class":323,"line":344},[321,2645,2615],{"class":855},[321,2647,2648],{"class":331}," context ",[321,2650,375],{"class":374},[321,2652,2653],{"class":331}," Context",[321,2655,275],{"class":501},[321,2657,1630],{"class":327},[321,2659,341],{"class":501},[321,2661,2662,2664,2666,2668,2670,2673,2675],{"class":323,"line":352},[321,2663,1637],{"class":501},[321,2665,645],{"class":327},[321,2667,393],{"class":501},[321,2669,921],{"class":525},[321,2671,2672],{"class":378},"user-id",[321,2674,921],{"class":525},[321,2676,399],{"class":501},[321,2678,2679,2681,2684,2686,2688,2691,2693],{"class":323,"line":360},[321,2680,1637],{"class":501},[321,2682,2683],{"class":327},"name",[321,2685,393],{"class":501},[321,2687,921],{"class":525},[321,2689,2690],{"class":378},"Example User",[321,2692,921],{"class":525},[321,2694,399],{"class":501},[321,2696,2697,2699,2702,2704,2706,2709,2711,2713,2715,2718,2720],{"class":323,"line":368},[321,2698,1637],{"class":501},[321,2700,2701],{"class":327},"trait",[321,2703,393],{"class":501},[321,2705,921],{"class":525},[321,2707,2708],{"class":378},"region",[321,2710,921],{"class":525},[321,2712,1136],{"class":501},[321,2714,1139],{"class":525},[321,2716,2717],{"class":378},"North America",[321,2719,921],{"class":525},[321,2721,399],{"class":501},[321,2723,2724,2726,2728],{"class":323,"line":382},[321,2725,1637],{"class":501},[321,2727,1676],{"class":327},[321,2729,960],{"class":501},[321,2731,2732],{"class":323,"line":402},[321,2733,455],{"emptyLinePlaceholder":54},[321,2735,2736,2738,2740,2742,2744,2746,2749,2751,2753,2755,2757,2760],{"class":323,"line":408},[321,2737,916],{"class":331},[321,2739,275],{"class":501},[321,2741,2281],{"class":327},[321,2743,393],{"class":501},[321,2745,921],{"class":525},[321,2747,2748],{"class":378},"my-boolean-config-key",[321,2750,921],{"class":525},[321,2752,1136],{"class":501},[321,2754,2296],{"class":2295},[321,2756,1136],{"class":501},[321,2758,2759],{"class":331}," context",[321,2761,929],{"class":501},[265,2763,2764,2766,2767,2770],{},[272,2765,2615],{}," is built with ",[272,2768,2769],{},"Context.builder()"," and accepts the following:",[1317,2772,2773,2782,2791,2826],{},[830,2774,2775,2777],{},[272,2776,645],{},[1317,2778,2779],{},[830,2780,2781],{},"The user's identifier. It decides their bucket in a percentage rollout, so changing it can move a user into a different percentile. If it is not provided, a percentage rollout assigns an unstable bucket.",[830,2783,2784,2786],{},[272,2785,2683],{},[1317,2787,2788],{},[830,2789,2790],{},"The user's display name.",[830,2792,2793,2796,2797,2800],{},[272,2794,2795],{},"trait(String key, Object value)"," \u002F ",[272,2798,2799],{},"traits(Map\u003CString, Object> traits)",[1317,2801,2802,2817],{},[830,2803,2804,2805,2509,2807,2509,2810,2509,2812,2509,2814,2816],{},"Arbitrary traits which can be referenced in targeting rules. Values are JSON-shaped: ",[272,2806,2232],{},[272,2808,2809],{},"Number",[272,2811,2508],{},[272,2813,2529],{},[272,2815,2183],{},", or null. Anything else has no text form and will not match a targeting rule.",[830,2818,2819,2821,2822,2825],{},[272,2820,2701],{}," adds a single trait, keeping the rest. ",[272,2823,2824],{},"traits"," replaces every trait set so far.",[830,2827,2828,2831],{},[272,2829,2830],{},"anonymous",[1317,2832,2833],{},[830,2834,2835],{},"Keeps the context out of the dashboard: it is evaluated but never persisted, and telemetry reports neither the context nor its id.",[1016,2837,2839],{"id":2838},"watch-for-updates","Watch for updates",[265,2841,2842],{},"The watches mirror the getters, one per type. Each accepts the config key, the default value used when an update will not convert to that type, a handler that runs when the config value is updated, and an optional user context as its last argument:",[1317,2844,2845,2850,2855,2860,2865,2870],{},[830,2846,2847],{},[272,2848,2849],{},"watchBoolean(String configKey, boolean defaultValue, Consumer\u003CBoolean> onChange)",[830,2851,2852],{},[272,2853,2854],{},"watchString(String configKey, String defaultValue, Consumer\u003CString> onChange)",[830,2856,2857],{},[272,2858,2859],{},"watchInteger(String configKey, int defaultValue, Consumer\u003CInteger> onChange)",[830,2861,2862],{},[272,2863,2864],{},"watchDouble(String configKey, double defaultValue, Consumer\u003CDouble> onChange)",[830,2866,2867],{},[272,2868,2869],{},"watchJsonObject(String configKey, Map\u003CString, Object> defaultValue, Consumer\u003CMap\u003CString, Object>> onChange)",[830,2871,2872],{},[272,2873,2874],{},"watchJsonArray(String configKey, List\u003CObject> defaultValue, Consumer\u003CList\u003CObject>> onChange)",[265,2876,2877,2878,2880],{},"Registering a watch before ",[272,2879,957],{}," means it is called for the first config state as well; one registered afterwards only sees later updates. When a full payload no longer includes the watched config, the handler is called with the default value, so it always agrees with what the getter would return. Handlers run on the transport thread, so one that blocks delays later updates.",[311,2882,2884],{"className":842,"code":2883,"filename":2149,"language":253,"meta":317,"style":317},"import com.configdirector.Context;\nimport com.configdirector.Subscription;\n\nSubscription subscription = client.watchBoolean(\n    \"new-checkout\",\n    false,\n    value -> System.out.println(\"new-checkout is now \" + value),\n    Context.builder()\n        .id(\"user-id\")\n        .name(\"Example User\")\n        .trait(\"region\", \"North America\")\n        .build());\n",[272,2885,2886,2902,2918,2922,2938,2948,2954,2985,2996,3012,3028,3052],{"__ignoreMap":317},[321,2887,2888,2890,2892,2894,2896,2898,2900],{"class":323,"line":324},[321,2889,852],{"class":851},[321,2891,856],{"class":855},[321,2893,275],{"class":501},[321,2895,651],{"class":855},[321,2897,275],{"class":501},[321,2899,2615],{"class":855},[321,2901,867],{"class":501},[321,2903,2904,2906,2908,2910,2912,2914,2916],{"class":323,"line":335},[321,2905,852],{"class":851},[321,2907,856],{"class":855},[321,2909,275],{"class":501},[321,2911,651],{"class":855},[321,2913,275],{"class":501},[321,2915,1898],{"class":855},[321,2917,867],{"class":501},[321,2919,2920],{"class":323,"line":344},[321,2921,455],{"emptyLinePlaceholder":54},[321,2923,2924,2926,2928,2930,2932,2934,2936],{"class":323,"line":352},[321,2925,1898],{"class":855},[321,2927,1911],{"class":331},[321,2929,375],{"class":374},[321,2931,1916],{"class":331},[321,2933,275],{"class":501},[321,2935,2388],{"class":327},[321,2937,1096],{"class":501},[321,2939,2940,2942,2944,2946],{"class":323,"line":360},[321,2941,1101],{"class":525},[321,2943,2288],{"class":378},[321,2945,921],{"class":525},[321,2947,1108],{"class":501},[321,2949,2950,2952],{"class":323,"line":368},[321,2951,2405],{"class":2295},[321,2953,1108],{"class":501},[321,2955,2956,2958,2960,2962,2964,2966,2968,2970,2972,2974,2976,2978,2980,2982],{"class":323,"line":382},[321,2957,2412],{"class":331},[321,2959,1117],{"class":1116},[321,2961,1931],{"class":331},[321,2963,275],{"class":501},[321,2965,1936],{"class":331},[321,2967,275],{"class":501},[321,2969,1941],{"class":327},[321,2971,393],{"class":501},[321,2973,921],{"class":525},[321,2975,2431],{"class":378},[321,2977,921],{"class":525},[321,2979,2436],{"class":374},[321,2981,2439],{"class":331},[321,2983,2984],{"class":501},"),\n",[321,2986,2987,2990,2992,2994],{"class":323,"line":402},[321,2988,2989],{"class":331},"    Context",[321,2991,275],{"class":501},[321,2993,1630],{"class":327},[321,2995,341],{"class":501},[321,2997,2998,3000,3002,3004,3006,3008,3010],{"class":323,"line":408},[321,2999,1524],{"class":501},[321,3001,645],{"class":327},[321,3003,393],{"class":501},[321,3005,921],{"class":525},[321,3007,2672],{"class":378},[321,3009,921],{"class":525},[321,3011,399],{"class":501},[321,3013,3014,3016,3018,3020,3022,3024,3026],{"class":323,"line":414},[321,3015,1524],{"class":501},[321,3017,2683],{"class":327},[321,3019,393],{"class":501},[321,3021,921],{"class":525},[321,3023,2690],{"class":378},[321,3025,921],{"class":525},[321,3027,399],{"class":501},[321,3029,3030,3032,3034,3036,3038,3040,3042,3044,3046,3048,3050],{"class":323,"line":422},[321,3031,1524],{"class":501},[321,3033,2701],{"class":327},[321,3035,393],{"class":501},[321,3037,921],{"class":525},[321,3039,2708],{"class":378},[321,3041,921],{"class":525},[321,3043,1136],{"class":501},[321,3045,1139],{"class":525},[321,3047,2717],{"class":378},[321,3049,921],{"class":525},[321,3051,399],{"class":501},[321,3053,3054,3056,3058],{"class":323,"line":435},[321,3055,1524],{"class":501},[321,3057,1676],{"class":327},[321,3059,3060],{"class":501},"());\n",[265,3062,3063,3064,3066],{},"Each watch returns a ",[272,3065,1898],{}," that cancels it when closed. Closing it twice is harmless.",[2597,3068,3069,3072,3073,3075,3076,3079,3080,298,3082,3084],{},[272,3070,3071],{},"watch",", which takes its type from the default value the way ",[272,3074,2501],{}," does, is deprecated as of ",[272,3077,3078],{},"1.1.0"," in favour of the typed watches above. It still works and is not scheduled for removal, and a ",[272,3081,2517],{},[272,3083,2523],{}," default — which no typed watch covers — still goes through it.",[260,3086,3088],{"id":3087},"other-useful-client-features","Other useful client features",[265,3090,3091],{},"The client provides additional methods.",[1016,3093,3095],{"id":3094},"isready",[272,3096,978],{},[265,3098,3099,3100,3102,3103,3105],{},"Returns a boolean indicating if the client has received config state and is ready to evaluate configs. It is initially ",[272,3101,720],{}," and becomes ",[272,3104,693],{}," once the first config state arrives. Until it does, every getter returns its default.",[1016,3107,3109],{"id":3108},"isclosed",[272,3110,3111],{},"isClosed",[265,3113,3114,3115,3117],{},"Returns a boolean indicating if ",[272,3116,281],{}," has been called. A closed client cannot be reopened.",[1016,3119,3121],{"id":3120},"getallconfigs",[272,3122,3123],{},"getAllConfigs",[265,3125,3126,3127,3130,3131,3133],{},"Returns every config the client currently holds as a ",[272,3128,3129],{},"Map\u003CString, ConfigState>",", evaluated but before type parsing. It optionally accepts a ",[272,3132,2615],{}," and a list of config keys to restrict the result to.",[265,3135,3136],{},"This is intended for handing state to a client SDK to hydrate with. It records no telemetry, since the SDK that receives the state reports its own evaluations.",[1016,3138,3140],{"id":3139},"unwatch",[272,3141,3139],{},[265,3143,3144],{},"Cancels every watch on one config key.",[1016,3146,3148],{"id":3147},"unwatchall",[272,3149,3150],{},"unwatchAll",[265,3152,3153],{},"Cancels every watch on every config key.",[1016,3155,3156],{"id":281},[272,3157,281],{},[265,3159,3160],{},"Closes all connections to ConfigDirector services, reports whatever telemetry is pending, and cancels every watch and event handler. Calling it twice is harmless.",[265,3162,3163,3164,3166,3167,3169,3170,3173],{},"Only call ",[272,3165,281],{}," when your application shuts down and it will no longer make use of the client instance. ",[272,3168,882],{}," implements ",[272,3171,3172],{},"AutoCloseable",", so in a container such as Spring it is enough to let the container own the lifecycle:",[311,3175,3178],{"className":842,"code":3176,"filename":3177,"language":253,"meta":317,"style":317},"@Bean(destroyMethod = \"close\")\npublic ConfigDirectorClient configDirectorClient() {\n  ConfigDirectorClient client = ConfigDirector.client(System.getenv(\"CONFIGDIRECTOR_SERVER_KEY\"));\n  client.initialize();\n  return client;\n}\n","ConfigDirectorConfiguration.java",[272,3179,3180,3205,3221,3257,3268,3278],{"__ignoreMap":317},[321,3181,3182,3185,3188,3190,3194,3197,3199,3201,3203],{"class":323,"line":324},[321,3183,3184],{"class":501},"@",[321,3186,3187],{"class":1116},"Bean",[321,3189,393],{"class":501},[321,3191,3193],{"class":3192},"sZMiF","destroyMethod",[321,3195,3196],{"class":374}," =",[321,3198,1139],{"class":525},[321,3200,281],{"class":378},[321,3202,921],{"class":525},[321,3204,399],{"class":501},[321,3206,3207,3210,3213,3216,3219],{"class":323,"line":335},[321,3208,3209],{"class":1116},"public",[321,3211,3212],{"class":855}," ConfigDirectorClient",[321,3214,3215],{"class":327}," configDirectorClient",[321,3217,3218],{"class":501},"()",[321,3220,332],{"class":501},[321,3222,3223,3226,3228,3230,3232,3234,3236,3238,3241,3243,3246,3248,3250,3253,3255],{"class":323,"line":344},[321,3224,3225],{"class":855},"  ConfigDirectorClient",[321,3227,906],{"class":331},[321,3229,375],{"class":374},[321,3231,911],{"class":331},[321,3233,275],{"class":501},[321,3235,916],{"class":327},[321,3237,393],{"class":501},[321,3239,3240],{"class":331},"System",[321,3242,275],{"class":501},[321,3244,3245],{"class":327},"getenv",[321,3247,393],{"class":501},[321,3249,921],{"class":525},[321,3251,3252],{"class":378},"CONFIGDIRECTOR_SERVER_KEY",[321,3254,921],{"class":525},[321,3256,1014],{"class":501},[321,3258,3259,3262,3264,3266],{"class":323,"line":352},[321,3260,3261],{"class":331},"  client",[321,3263,275],{"class":501},[321,3265,957],{"class":327},[321,3267,960],{"class":501},[321,3269,3270,3274,3276],{"class":323,"line":360},[321,3271,3273],{"class":3272},"sVHd0","  return",[321,3275,1916],{"class":331},[321,3277,867],{"class":501},[321,3279,3280],{"class":323,"line":368},[321,3281,449],{"class":501},[260,3283,3285],{"id":3284},"test-your-code","Test your code",[265,3287,3288,3289,3292,3293,3297],{},"Use the SDK's testing artifact, ",[272,3290,3291],{},"com.configdirector:server-sdk-testing",", to test the code that reads your configs and flags. It creates a ",[3294,3295,3296],"strong",{},"test client",": the SDK's real client connected to an in-memory server that your test controls. Only the connection to ConfigDirector is replaced. Everything else is the same code that runs in production, so the code under test behaves exactly as it does against ConfigDirector, and no network connection is opened and no telemetry is sent.",[265,3299,3300,3301,3303],{},"The artifact is released together with the SDK and must be the same version as the ",[272,3302,789],{}," on your test classpath. Add it in test scope:",[311,3305,3307],{"className":484,"code":3306,"filename":486,"language":487,"meta":317,"style":317},"testImplementation 'com.configdirector:server-sdk-testing:1.8.1'\n",[272,3308,3309],{"__ignoreMap":317},[321,3310,3311,3314,3316,3319],{"class":323,"line":324},[321,3312,3313],{"class":331},"testImplementation ",[321,3315,566],{"class":525},[321,3317,3318],{"class":378},"com.configdirector:server-sdk-testing:1.8.1",[321,3320,532],{"class":525},[311,3322,3325],{"className":842,"code":3323,"filename":3324,"language":253,"meta":317,"style":317},"import com.configdirector.testing.ConfigDirectorTesting;\nimport com.configdirector.testing.TestClient;\n\ntry (TestClient testClient = ConfigDirectorTesting.createTestClient(Map.of(\"new-checkout\", true, \"max-items\", 20))) {\n  CheckoutService service = new CheckoutService(testClient.client());\n  testClient.client().initialize();\n\n  assertThat(service.isNewCheckoutEnabled(\"user-123\")).isTrue();\n\n  testClient.setValue(\"new-checkout\", false);\n  assertThat(service.isNewCheckoutEnabled(\"user-123\")).isFalse();\n}\n","CheckoutServiceTest.java",[272,3326,3327,3349,3370,3374,3437,3464,3480,3484,3516,3520,3543,3570],{"__ignoreMap":317},[321,3328,3329,3331,3333,3335,3337,3339,3342,3344,3347],{"class":323,"line":324},[321,3330,852],{"class":851},[321,3332,856],{"class":855},[321,3334,275],{"class":501},[321,3336,651],{"class":855},[321,3338,275],{"class":501},[321,3340,3341],{"class":855},"testing",[321,3343,275],{"class":501},[321,3345,3346],{"class":855},"ConfigDirectorTesting",[321,3348,867],{"class":501},[321,3350,3351,3353,3355,3357,3359,3361,3363,3365,3368],{"class":323,"line":335},[321,3352,852],{"class":851},[321,3354,856],{"class":855},[321,3356,275],{"class":501},[321,3358,651],{"class":855},[321,3360,275],{"class":501},[321,3362,3341],{"class":855},[321,3364,275],{"class":501},[321,3366,3367],{"class":855},"TestClient",[321,3369,867],{"class":501},[321,3371,3372],{"class":323,"line":344},[321,3373,455],{"emptyLinePlaceholder":54},[321,3375,3376,3379,3382,3384,3387,3389,3392,3394,3397,3399,3401,3403,3405,3407,3409,3411,3413,3415,3418,3420,3422,3425,3427,3429,3432,3435],{"class":323,"line":352},[321,3377,3378],{"class":3272},"try",[321,3380,3381],{"class":501}," (",[321,3383,3367],{"class":855},[321,3385,3386],{"class":331}," testClient ",[321,3388,375],{"class":374},[321,3390,3391],{"class":331}," ConfigDirectorTesting",[321,3393,275],{"class":501},[321,3395,3396],{"class":327},"createTestClient",[321,3398,393],{"class":501},[321,3400,2183],{"class":331},[321,3402,275],{"class":501},[321,3404,2344],{"class":327},[321,3406,393],{"class":501},[321,3408,921],{"class":525},[321,3410,2288],{"class":378},[321,3412,921],{"class":525},[321,3414,1136],{"class":501},[321,3416,3417],{"class":2295}," true",[321,3419,1136],{"class":501},[321,3421,1139],{"class":525},[321,3423,3424],{"class":378},"max-items",[321,3426,921],{"class":525},[321,3428,1136],{"class":501},[321,3430,3431],{"class":1010}," 20",[321,3433,3434],{"class":501},")))",[321,3436,332],{"class":501},[321,3438,3439,3442,3445,3447,3450,3453,3455,3458,3460,3462],{"class":323,"line":360},[321,3440,3441],{"class":855},"  CheckoutService",[321,3443,3444],{"class":331}," service ",[321,3446,375],{"class":374},[321,3448,3449],{"class":3272}," new",[321,3451,3452],{"class":327}," CheckoutService",[321,3454,393],{"class":501},[321,3456,3457],{"class":331},"testClient",[321,3459,275],{"class":501},[321,3461,916],{"class":327},[321,3463,3060],{"class":501},[321,3465,3466,3469,3471,3473,3476,3478],{"class":323,"line":368},[321,3467,3468],{"class":331},"  testClient",[321,3470,275],{"class":501},[321,3472,916],{"class":327},[321,3474,3475],{"class":501},"().",[321,3477,957],{"class":327},[321,3479,960],{"class":501},[321,3481,3482],{"class":323,"line":382},[321,3483,455],{"emptyLinePlaceholder":54},[321,3485,3486,3489,3491,3494,3496,3499,3501,3503,3506,3508,3511,3514],{"class":323,"line":402},[321,3487,3488],{"class":327},"  assertThat",[321,3490,393],{"class":501},[321,3492,3493],{"class":331},"service",[321,3495,275],{"class":501},[321,3497,3498],{"class":327},"isNewCheckoutEnabled",[321,3500,393],{"class":501},[321,3502,921],{"class":525},[321,3504,3505],{"class":378},"user-123",[321,3507,921],{"class":525},[321,3509,3510],{"class":501},")).",[321,3512,3513],{"class":327},"isTrue",[321,3515,960],{"class":501},[321,3517,3518],{"class":323,"line":408},[321,3519,455],{"emptyLinePlaceholder":54},[321,3521,3522,3524,3526,3529,3531,3533,3535,3537,3539,3541],{"class":323,"line":414},[321,3523,3468],{"class":331},[321,3525,275],{"class":501},[321,3527,3528],{"class":327},"setValue",[321,3530,393],{"class":501},[321,3532,921],{"class":525},[321,3534,2288],{"class":378},[321,3536,921],{"class":525},[321,3538,1136],{"class":501},[321,3540,2296],{"class":2295},[321,3542,929],{"class":501},[321,3544,3545,3547,3549,3551,3553,3555,3557,3559,3561,3563,3565,3568],{"class":323,"line":422},[321,3546,3488],{"class":327},[321,3548,393],{"class":501},[321,3550,3493],{"class":331},[321,3552,275],{"class":501},[321,3554,3498],{"class":327},[321,3556,393],{"class":501},[321,3558,921],{"class":525},[321,3560,3505],{"class":378},[321,3562,921],{"class":525},[321,3564,3510],{"class":501},[321,3566,3567],{"class":327},"isFalse",[321,3569,960],{"class":501},[321,3571,3572],{"class":323,"line":435},[321,3573,449],{"class":501},[265,3575,3576,3579,3580,3582,3583,3585,3586,3588,3589,3591,3592,3594],{},[272,3577,3578],{},"testClient.client()"," is a ",[272,3581,882],{},", so it goes anywhere your code accepts one. It starts uninitialized, like a production client, because the code under test usually owns the call to ",[272,3584,957],{},"; with no hold or failure armed, ",[272,3587,957],{}," completes at once with the stored values. ",[272,3590,3367],{}," is ",[272,3593,3172],{}," and closes its client.",[1016,3596,3598],{"id":3597},"with-junit-jupiter","With JUnit Jupiter",[265,3600,3601,3604],{},[272,3602,3603],{},"ConfigDirectorTestExtension"," creates one test client per test, seeds it from annotations on the test class and the test method, injects it, and closes it after the test. Annotations on the class apply to every test; annotations on a method add to or override them.",[311,3606,3609],{"className":842,"code":3607,"filename":3608,"language":253,"meta":317,"style":317},"@ExtendWith(ConfigDirectorTestExtension.class)\nclass CheckoutTest {\n\n  @Test\n  @BooleanConfigValue(key = \"new-checkout\", value = true)\n  @IntegerConfigValue(key = \"max-items\", value = 20)\n  @JsonConfigValue(key = \"theme\", value = \"{\\\"color\\\": \\\"blue\\\"}\")\n  void showsTheNewCheckout(TestClient testClient) {\n    testClient.client().initialize();\n    ...\n  }\n}\n","CheckoutTest.java",[272,3610,3611,3629,3639,3643,3651,3681,3710,3766,3787,3802,3807,3812],{"__ignoreMap":317},[321,3612,3613,3615,3618,3620,3622,3624,3627],{"class":323,"line":324},[321,3614,3184],{"class":501},[321,3616,3617],{"class":1116},"ExtendWith",[321,3619,393],{"class":501},[321,3621,3603],{"class":331},[321,3623,275],{"class":501},[321,3625,3626],{"class":331},"class",[321,3628,399],{"class":501},[321,3630,3631,3633,3637],{"class":323,"line":335},[321,3632,3626],{"class":1116},[321,3634,3636],{"class":3635},"sbgvK"," CheckoutTest",[321,3638,332],{"class":501},[321,3640,3641],{"class":323,"line":344},[321,3642,455],{"emptyLinePlaceholder":54},[321,3644,3645,3648],{"class":323,"line":352},[321,3646,3647],{"class":501},"  @",[321,3649,3650],{"class":1116},"Test\n",[321,3652,3653,3655,3658,3660,3663,3665,3667,3669,3671,3673,3675,3677,3679],{"class":323,"line":360},[321,3654,3647],{"class":501},[321,3656,3657],{"class":1116},"BooleanConfigValue",[321,3659,393],{"class":501},[321,3661,3662],{"class":3192},"key",[321,3664,3196],{"class":374},[321,3666,1139],{"class":525},[321,3668,2288],{"class":378},[321,3670,921],{"class":525},[321,3672,1136],{"class":501},[321,3674,2439],{"class":3192},[321,3676,3196],{"class":374},[321,3678,3417],{"class":2295},[321,3680,399],{"class":501},[321,3682,3683,3685,3688,3690,3692,3694,3696,3698,3700,3702,3704,3706,3708],{"class":323,"line":368},[321,3684,3647],{"class":501},[321,3686,3687],{"class":1116},"IntegerConfigValue",[321,3689,393],{"class":501},[321,3691,3662],{"class":3192},[321,3693,3196],{"class":374},[321,3695,1139],{"class":525},[321,3697,3424],{"class":378},[321,3699,921],{"class":525},[321,3701,1136],{"class":501},[321,3703,2439],{"class":3192},[321,3705,3196],{"class":374},[321,3707,3431],{"class":1010},[321,3709,399],{"class":501},[321,3711,3712,3714,3717,3719,3721,3723,3725,3727,3729,3731,3733,3735,3737,3740,3744,3747,3749,3752,3754,3757,3759,3762,3764],{"class":323,"line":382},[321,3713,3647],{"class":501},[321,3715,3716],{"class":1116},"JsonConfigValue",[321,3718,393],{"class":501},[321,3720,3662],{"class":3192},[321,3722,3196],{"class":374},[321,3724,1139],{"class":525},[321,3726,2251],{"class":378},[321,3728,921],{"class":525},[321,3730,1136],{"class":501},[321,3732,2439],{"class":3192},[321,3734,3196],{"class":374},[321,3736,1139],{"class":525},[321,3738,3739],{"class":378},"{",[321,3741,3743],{"class":3742},"s_hVV","\\\"",[321,3745,3746],{"class":378},"color",[321,3748,3743],{"class":3742},[321,3750,3751],{"class":378},": ",[321,3753,3743],{"class":3742},[321,3755,3756],{"class":378},"blue",[321,3758,3743],{"class":3742},[321,3760,3761],{"class":378},"}",[321,3763,921],{"class":525},[321,3765,399],{"class":501},[321,3767,3768,3771,3774,3776,3778,3782,3785],{"class":323,"line":402},[321,3769,3770],{"class":1116},"  void",[321,3772,3773],{"class":327}," showsTheNewCheckout",[321,3775,393],{"class":501},[321,3777,3367],{"class":855},[321,3779,3781],{"class":3780},"s99_P"," testClient",[321,3783,3784],{"class":501},")",[321,3786,332],{"class":501},[321,3788,3789,3792,3794,3796,3798,3800],{"class":323,"line":408},[321,3790,3791],{"class":331},"    testClient",[321,3793,275],{"class":501},[321,3795,916],{"class":327},[321,3797,3475],{"class":501},[321,3799,957],{"class":327},[321,3801,960],{"class":501},[321,3803,3804],{"class":323,"line":414},[321,3805,3806],{"class":501},"    ...\n",[321,3808,3809],{"class":323,"line":422},[321,3810,3811],{"class":501},"  }\n",[321,3813,3814],{"class":323,"line":435},[321,3815,449],{"class":501},[265,3817,3818,3819,2509,3822,3825,3826,3829,3830,3825,3833,3829,3836,3839,3840,3843,3844,3846,3847,3849,3850,3852],{},"Each config type has its own annotation, because annotation attributes are compile-time constants: ",[272,3820,3821],{},"@BooleanConfigValue",[272,3823,3824],{},"@IntegerConfigValue"," (a ",[272,3827,3828],{},"long","), ",[272,3831,3832],{},"@FloatConfigValue",[272,3834,3835],{},"double",[272,3837,3838],{},"@StringConfigValue",", and ",[272,3841,3842],{},"@JsonConfigValue",", whose ",[272,3845,2060],{}," is strict JSON text holding an object or an array. A ",[272,3848,882],{}," parameter resolves to the same client as a ",[272,3851,3367],{}," parameter. The extension works with JUnit 5.10 or newer and JUnit 6.",[1016,3854,3856],{"id":3855},"application-contexts-shared-across-tests","Application contexts shared across tests",[265,3858,3859,3860,3863,3864,3866,3867,3870],{},"The extension is for code that receives the client from the test. A Spring, Micronaut, or Quarkus context that outlives a test keeps one test client in a static field, ",[3294,3861,3862],{},"replaces"," the application's client bean with ",[272,3865,3578],{},", initializes it where the application's own bean method would have, and calls ",[272,3868,3869],{},"replaceValues"," in each test's setup. Replacing matters: a second bean leaves the application's own client in place, which connects to ConfigDirector on startup.",[3872,3873,3874,3887],"table",{},[3875,3876,3877],"thead",{},[3878,3879,3880,3884],"tr",{},[3881,3882,3883],"th",{},"Container",[3881,3885,3886],{},"Replacement",[3888,3889,3890,3913,3924],"tbody",{},[3878,3891,3892,3896],{},[3893,3894,3895],"td",{},"Spring Framework 6.2 and later",[3893,3897,3898,3901,3902,3904,3905,3908,3909,3912],{},[272,3899,3900],{},"@TestBean"," on a field of type ",[272,3903,882],{},", with a static factory method in the test class that initializes and returns the static test client's ",[272,3906,3907],{},"client()",". A second ",[272,3910,3911],{},"@Primary"," bean is not enough, and reusing the bean name fails because Spring Boot disables bean overriding by default.",[3878,3914,3915,3918],{},[3893,3916,3917],{},"Micronaut",[3893,3919,3920,3921,275],{},"A test factory method with ",[272,3922,3923],{},"@Replaces(bean = ConfigDirectorClient.class, factory = YourConfigDirectorFactory.class)",[3878,3925,3926,3929],{},[3893,3927,3928],{},"Quarkus",[3893,3930,3931,3932,3935,3936,3939,3940,3943,3944,3947,3948,3951],{},"A ",[272,3933,3934],{},"@io.quarkus.test.Mock"," producer, scoped ",[272,3937,3938],{},"@Singleton",", plus a ",[272,3941,3942],{},"QuarkusTestProfile"," whose ",[272,3945,3946],{},"quarkus.arc.exclude-types"," names the application's producer class: ",[272,3949,3950],{},"@Startup"," on that producer still builds and initializes the original client even though injection points receive the mock (checked with Quarkus 3.39). Excluding the class removes every producer in it, so anything else it produced comes from the test producer too.",[1016,3953,3955],{"id":3954},"values","Values",[265,3957,3958,2509,3960,3839,3962,3964,3965,3967,3968,298,3970,3972,3973,298,3975,3977,3978,3980,3981,3983,3984,3986,3987,3989,3990,3993,3994,3996,3997,3999,4000,4002,4003,4005,4006,4009,4010,4012,4013,4015,4016,4018],{},[272,3959,3396],{},[272,3961,3528],{},[272,3963,3869],{}," take native values, and the config type follows from each value: a ",[272,3966,2508],{},", an ",[272,3969,2514],{},[272,3971,2517],{}," (an integer config), a ",[272,3974,2523],{},[272,3976,2520],{}," (a float config), a ",[272,3979,2232],{},", or a ",[272,3982,2183],{}," with ",[272,3985,2232],{}," keys or a ",[272,3988,2529],{}," (a JSON config). ",[272,3991,3992],{},"setJsonValue"," takes strict JSON text holding an object or an array; a ",[272,3995,2232],{}," given to ",[272,3998,3528],{}," is always a string config. Every value is served as an unconditional config, so every context receives the same value; a test that needs different values per context is written as one test per value. A ",[272,4001,2134],{}," value, a blank key, a non-finite number, another ",[272,4004,2809],{}," subclass such as ",[272,4007,4008],{},"BigDecimal",", a ",[272,4011,2183],{}," with non-",[272,4014,2232],{}," keys, or JSON contents that cannot be encoded throw ",[272,4017,1887],{},", and nothing changes.",[265,4020,4021,4022,4025,4026,4028,4029,4032,4033,4035,4036,4038,4039,4041,4042,4045,4046,275],{},"Reads behave as they do in production: ",[272,4023,4024],{},"setValue(\"k\", true)"," read as a string returns the in-code default value with the ",[272,4027,2118],{}," reason, and ",[272,4030,4031],{},"setValue(\"k\", \"\")"," serves the in-code default value with the ",[272,4034,2124],{}," reason. Numbers inside JSON configs come back as ",[272,4037,2517],{}," and ",[272,4040,2520],{},", so ",[272,4043,4044],{},"Map.of(\"n\", 1)"," reads back as ",[272,4047,4048],{},"{n=1L}",[1016,4050,4052],{"id":4051},"controls","Controls",[3872,4054,4055,4065],{},[3875,4056,4057],{},[3878,4058,4059,4062],{},[3881,4060,4061],{},"Control",[3881,4063,4064],{},"Effect",[3888,4066,4067,4086,4099,4124,4134,4157,4169],{},[3878,4068,4069,4074],{},[3893,4070,4071],{},[272,4072,4073],{},"setValue(key, value)",[3893,4075,4076,4077,4079,4080,2509,4082,4085],{},"Stores the value and, once the client is connected, delivers an update carrying only ",[272,4078,3662],{},". Watches of ",[272,4081,3662],{},[272,4083,4084],{},"configsUpdated"," handlers, and reads see it before the call returns.",[3878,4087,4088,4093],{},[3893,4089,4090],{},[272,4091,4092],{},"setJsonValue(key, json)",[3893,4094,4095,4096,4098],{},"As ",[272,4097,3528],{},", for strict JSON text that becomes a JSON config.",[3878,4100,4101,4106],{},[3893,4102,4103],{},[272,4104,4105],{},"removeValue(key)",[3893,4107,4108,4109,4111,4112,4114,4115,4117,4118,4120,4121,275],{},"Removes the value and delivers a full update without it. Reads return the in-code default value with the ",[272,4110,2094],{}," reason, watches of ",[272,4113,3662],{}," receive the default, and ",[272,4116,4084],{}," lists ",[272,4119,3662],{}," in ",[272,4122,4123],{},"removedKeys()",[3878,4125,4126,4131],{},[3893,4127,4128],{},[272,4129,4130],{},"replaceValues(values)",[3893,4132,4133],{},"Replaces every stored value, disarms any armed hold or failure, and delivers a full update. Use it to reset a test client shared across tests.",[3878,4135,4136,4141],{},[3893,4137,4138],{},[272,4139,4140],{},"holdInitialization()",[3893,4142,4143,4144,4146,4147,298,4150,4153,4154,4156],{},"The next ",[272,4145,957],{}," waits until ",[272,4148,4149],{},"completeInitialization()",[272,4151,4152],{},"failInitialization()",", or until the client's timeout elapses. ",[272,4155,957],{}," blocks, so a test calls it on another thread.",[3878,4158,4159,4163],{},[3893,4160,4161],{},[272,4162,4149],{},[3893,4164,4165,4166,4168],{},"Delivers the stored values to the held ",[272,4167,957],{},", on the calling thread, so the client is ready when the call returns. Called while a hold is armed but not picked up, it disarms the hold.",[3878,4170,4171,4175],{},[3893,4172,4173],{},[272,4174,4152],{},[3893,4176,4177,4178,4180,4181,4183],{},"Fails the held ",[272,4179,957],{}," the way an invalid SDK key does: it completes promptly, the client is not ready, and the error is logged. Called with no ",[272,4182,957],{}," held, it arms the next one to fail.",[265,4185,4186,4187,4189],{},"After a failed attempt, the next ",[272,4188,957],{}," succeeds and delivers the values stored in the meantime.",[311,4191,4193],{"className":842,"code":4192,"filename":3324,"language":253,"meta":317,"style":317},"try (TestClient testClient =\n    ConfigDirectorTesting.createTestClient(Map.of(\"new-checkout\", true), options -> options.timeout(Duration.ofMillis(500)))) {\n  testClient.failInitialization();\n\n  testClient.client().initialize();\n\n  assertThat(testClient.client().isReady()).isFalse();\n  assertThat(service.isNewCheckoutEnabled(\"user-123\")).isFalse();\n}\n",[272,4194,4195,4208,4270,4281,4285,4299,4303,4326,4352],{"__ignoreMap":317},[321,4196,4197,4199,4201,4203,4205],{"class":323,"line":324},[321,4198,3378],{"class":3272},[321,4200,3381],{"class":501},[321,4202,3367],{"class":855},[321,4204,3386],{"class":331},[321,4206,4207],{"class":374},"=\n",[321,4209,4210,4213,4215,4217,4219,4221,4223,4225,4227,4229,4231,4233,4235,4237,4240,4243,4245,4247,4249,4251,4253,4255,4257,4260,4262,4265,4268],{"class":323,"line":335},[321,4211,4212],{"class":331},"    ConfigDirectorTesting",[321,4214,275],{"class":501},[321,4216,3396],{"class":327},[321,4218,393],{"class":501},[321,4220,2183],{"class":331},[321,4222,275],{"class":501},[321,4224,2344],{"class":327},[321,4226,393],{"class":501},[321,4228,921],{"class":525},[321,4230,2288],{"class":378},[321,4232,921],{"class":525},[321,4234,1136],{"class":501},[321,4236,3417],{"class":2295},[321,4238,4239],{"class":501},"),",[321,4241,4242],{"class":331}," options ",[321,4244,1117],{"class":1116},[321,4246,1120],{"class":331},[321,4248,275],{"class":501},[321,4250,1382],{"class":327},[321,4252,393],{"class":501},[321,4254,982],{"class":331},[321,4256,275],{"class":501},[321,4258,4259],{"class":327},"ofMillis",[321,4261,393],{"class":501},[321,4263,4264],{"class":1010},"500",[321,4266,4267],{"class":501},"))))",[321,4269,332],{"class":501},[321,4271,4272,4274,4276,4279],{"class":323,"line":344},[321,4273,3468],{"class":331},[321,4275,275],{"class":501},[321,4277,4278],{"class":327},"failInitialization",[321,4280,960],{"class":501},[321,4282,4283],{"class":323,"line":352},[321,4284,455],{"emptyLinePlaceholder":54},[321,4286,4287,4289,4291,4293,4295,4297],{"class":323,"line":360},[321,4288,3468],{"class":331},[321,4290,275],{"class":501},[321,4292,916],{"class":327},[321,4294,3475],{"class":501},[321,4296,957],{"class":327},[321,4298,960],{"class":501},[321,4300,4301],{"class":323,"line":368},[321,4302,455],{"emptyLinePlaceholder":54},[321,4304,4305,4307,4309,4311,4313,4315,4317,4319,4322,4324],{"class":323,"line":382},[321,4306,3488],{"class":327},[321,4308,393],{"class":501},[321,4310,3457],{"class":331},[321,4312,275],{"class":501},[321,4314,916],{"class":327},[321,4316,3475],{"class":501},[321,4318,978],{"class":327},[321,4320,4321],{"class":501},"()).",[321,4323,3567],{"class":327},[321,4325,960],{"class":501},[321,4327,4328,4330,4332,4334,4336,4338,4340,4342,4344,4346,4348,4350],{"class":323,"line":402},[321,4329,3488],{"class":327},[321,4331,393],{"class":501},[321,4333,3493],{"class":331},[321,4335,275],{"class":501},[321,4337,3498],{"class":327},[321,4339,393],{"class":501},[321,4341,921],{"class":525},[321,4343,3505],{"class":378},[321,4345,921],{"class":525},[321,4347,3510],{"class":501},[321,4349,3567],{"class":327},[321,4351,960],{"class":501},[321,4353,4354],{"class":323,"line":408},[321,4355,449],{"class":501},[1016,4357,4359],{"id":4358},"options","Options",[265,4361,4362,4365,4366,4368,4369,4371,4372,4374,4375,4377],{},[272,4363,4364],{},"createTestClient(values, options -> ...)"," takes ",[272,4367,1382],{}," (the client's connection timeout, which bounds how long a held ",[272,4370,957],{}," waits; defaults to the SDK's production timeout) and ",[272,4373,1163],{}," (defaults to the SDK's logger, ",[272,4376,569],{},").",[1016,4379,4381],{"id":4380},"what-to-expect","What to expect",[1317,4383,4384,4399,4415,4427,4435,4449],{},[830,4385,4386,4387,4389,4390,4392,4393,4395,4396,275],{},"The first update is delivered while ",[272,4388,957],{}," connects, so watches registered before ",[272,4391,957],{}," run before it returns, and ",[272,4394,4084],{}," fires before ",[272,4397,4398],{},"clientReady",[830,4400,4401,4402,2509,4404,2509,4407,2509,4409,2526,4412,4414],{},"Watches and handlers run on the thread that calls ",[272,4403,3528],{},[272,4405,4406],{},"removeValue",[272,4408,3869],{},[272,4410,4411],{},"completeInitialization",[272,4413,957],{},", not on a transport thread.",[830,4416,4417,4418,4420,4421,4423,4424,4426],{},"A held ",[272,4419,957],{}," that times out, or that is interrupted by ",[272,4422,281],{},", leaves the client not ready until the next ",[272,4425,957],{},", and logs the SDK's timeout warning; production streaming would keep retrying in the background.",[830,4428,4429,4430,4038,4432,4434],{},"Watches fire on every update carrying their key, whether or not the value changed, as in production. ",[272,4431,4406],{},[272,4433,3869],{}," deliver a full update, so they also fire the watches of every remaining key.",[830,4436,3931,4437,4440,4441,4444,4445,4448],{},[272,4438,4439],{},"RuntimeException"," thrown by a watch or handler is logged and does not propagate, as with the production transports. An ",[272,4442,4443],{},"Error",", such as a failed assertion's ",[272,4446,4447],{},"AssertionError",", propagates out of the call that delivered the update.",[830,4450,4451,4452,4454,4455,4457,4458,4460,4461,4463,4464,4466],{},"After ",[272,4453,281],{},", reads return the in-code default value with the ",[272,4456,2088],{}," reason, ",[272,4459,3123],{}," returns an empty map, ",[272,4462,957],{}," throws ",[272,4465,1887],{},", the test client's controls are silent no-ops, and no SDK thread is left running.",[4468,4469,4470],"style",{},"html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sQzsp, html code.shiki .sQzsp{--shiki-light:#E53935;--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sw1J6, html code.shiki .sw1J6{--shiki-light:#F76D47;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .s_bVq, html code.shiki .s_bVq{--shiki-light:#9C3EDA;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .s9AJx, html code.shiki .s9AJx{--shiki-light:#9C3EDA;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZMiF, html code.shiki .sZMiF{--shiki-light:#E2931D;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVHd0, html code.shiki .sVHd0{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s99_P, html code.shiki .s99_P{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}",{"title":317,"searchDepth":335,"depth":335,"links":4472},[4473,4474,4475,4479,4483,4491],{"id":262,"depth":335,"text":263},{"id":285,"depth":335,"text":286},{"id":824,"depth":335,"text":825,"children":4476},[4477,4478],{"id":1018,"depth":344,"text":1019},{"id":1891,"depth":344,"text":1892},{"id":2141,"depth":335,"text":2142,"children":4480},[4481,4482],{"id":2605,"depth":344,"text":2606},{"id":2838,"depth":344,"text":2839},{"id":3087,"depth":335,"text":3088,"children":4484},[4485,4486,4487,4488,4489,4490],{"id":3094,"depth":344,"text":978},{"id":3108,"depth":344,"text":3111},{"id":3120,"depth":344,"text":3123},{"id":3139,"depth":344,"text":3139},{"id":3147,"depth":344,"text":3150},{"id":281,"depth":344,"text":281},{"id":3284,"depth":335,"text":3285,"children":4492},[4493,4494,4495,4496,4497,4498],{"id":3597,"depth":344,"text":3598},{"id":3855,"depth":344,"text":3856},{"id":3954,"depth":344,"text":3955},{"id":4051,"depth":344,"text":4052},{"id":4358,"depth":344,"text":4359},{"id":4380,"depth":344,"text":4381},"Evaluate configs and feature flags locally for any user context with the Java server SDK, with updates delivered over server sent events","md",null,{"modifiedAt":4503},"2026-10-12T00:22:49.000Z",{"title":167,"icon":170},{"title":246,"description":4499},"wcAsL6AR-lLtMF-NJQWW6nbhDky88JxgLIfwQrtUEdk",[4508,4510],{"title":162,"path":163,"stem":164,"description":4509,"icon":165,"children":-1},"Evaluate configs and feature flags locally for any user context with the Python server SDK, with updates delivered over server sent events",{"title":172,"path":173,"stem":174,"description":4511,"icon":175,"children":-1},"Evaluate configs and feature flags locally for any user context with the .NET server SDK, with updates delivered over server sent events",1791783866602]