or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

build-integration.mdimage-packaging.mdindex.mdjar-writing.mdlaunch-scripts.mdlayer-support.mdlayout-management.mdlibrary-management.mdmain-class-detection.mdrepackaging.md

layout-management.mddocs/

0

# Archive Layout Management

1

2

Strategy-based system for determining how classes and libraries are organized within different archive types. The layout system supports JAR, WAR, and expanded directory structures with extensive customization options for different deployment scenarios.

3

4

## Capabilities

5

6

### Layout Interface

7

8

Core interface defining how archive contents are organized and accessed by the Spring Boot loader.

9

10

```java { .api }

11

public interface Layout {

12

/**

13

* Get the launcher class name for this layout.

14

* The launcher is responsible for bootstrapping the application.

15

*

16

* @return the fully qualified launcher class name

17

*/

18

String getLauncherClassName();

19

20

/**

21

* Get the location where a library should be placed within the archive.

22

*

23

* @param libraryName the name of the library

24

* @param scope the scope of the library (COMPILE, RUNTIME, etc.)

25

* @return the path within the archive where the library should be placed

26

*/

27

String getLibraryLocation(String libraryName, LibraryScope scope);

28

29

/**

30

* Get the location where application classes are stored.

31

*

32

* @return the path within the archive where classes are located

33

*/

34

String getClassesLocation();

35

36

/**

37

* Get the location of the classpath index file.

38

* Default implementation returns "BOOT-INF/classpath.idx".

39

*

40

* @return the path to the classpath index file

41

*/

42

default String getClasspathIndexFileLocation() {

43

return "BOOT-INF/classpath.idx";

44

}

45

46

/**

47

* Get the location of the layers index file.

48

* Default implementation returns "BOOT-INF/layers.idx".

49

*

50

* @return the path to the layers index file

51

*/

52

default String getLayersIndexFileLocation() {

53

return "BOOT-INF/layers.idx";

54

}

55

56

/**

57

* Determine if this layout produces executable archives.

58

*

59

* @return true if the archive can be executed directly

60

*/

61

boolean isExecutable();

62

}

63

```

64

65

### Repackaging Layout

66

67

Specialized layout interface for repackaging existing archives with different class locations.

68

69

```java { .api }

70

public interface RepackagingLayout extends Layout {

71

/**

72

* Get the location where repackaged classes should be stored.

73

* This may differ from the original classes location.

74

*

75

* @return the path for repackaged classes

76

*/

77

String getRepackagedClassesLocation();

78

}

79

```

80

81

### Custom Loader Layout

82

83

Interface for layouts that provide their own loader classes instead of using the standard Spring Boot loader.

84

85

```java { .api }

86

public interface CustomLoaderLayout {

87

/**

88

* Write custom loader classes to the archive.

89

*

90

* @param writer the writer for adding loader classes

91

* @throws IOException if writing fails

92

*/

93

void writeLoadedClasses(LoaderClassesWriter writer) throws IOException;

94

}

95

```

96

97

### Standard Layouts

98

99

Pre-defined layout implementations for common archive types.

100

101

```java { .api }

102

public final class Layouts {

103

/**

104

* Get the appropriate layout for the given file based on its extension and type.

105

*

106

* @param file the file to determine layout for

107

* @return the appropriate layout

108

*/

109

public static Layout forFile(File file);

110

111

/**

112

* Standard JAR layout for executable JAR files.

113

* Places libraries in BOOT-INF/lib/ and classes in BOOT-INF/classes/.

114

*/

115

public static class Jar implements RepackagingLayout {

116

@Override

117

public String getLauncherClassName() {

118

return "org.springframework.boot.loader.launch.JarLauncher";

119

}

120

121

@Override

122

public String getLibraryLocation(String libraryName, LibraryScope scope) {

123

return "BOOT-INF/lib/";

124

}

125

126

@Override

127

public String getClassesLocation() {

128

return "BOOT-INF/classes/";

129

}

130

131

@Override

132

public String getRepackagedClassesLocation() {

133

return "BOOT-INF/classes/";

134

}

135

136

@Override

137

public boolean isExecutable() {

138

return true;

139

}

140

}

141

142

/**

143

* Expanded JAR layout for directory-based deployment.

144

* Similar to JAR layout but optimized for exploded directory structure.

145

*/

146

public static class Expanded extends Jar {

147

@Override

148

public String getLauncherClassName() {

149

return "org.springframework.boot.loader.launch.PropertiesLauncher";

150

}

151

}

152

153

/**

154

* No-operation layout that preserves original structure.

155

* Used when no repackaging is desired.

156

*/

157

public static class None extends Jar {

158

@Override

159

public boolean isExecutable() {

160

return false;

161

}

162

}

163

164

/**

165

* WAR layout for web application archives.

166

* Places libraries in WEB-INF/lib/ and classes in WEB-INF/classes/.

167

*/

168

public static class War implements Layout {

169

@Override

170

public String getLauncherClassName() {

171

return "org.springframework.boot.loader.launch.WarLauncher";

172

}

173

174

@Override

175

public String getLibraryLocation(String libraryName, LibraryScope scope) {

176

if (scope == LibraryScope.PROVIDED) {

177

return "WEB-INF/lib-provided/";

178

}

179

return "WEB-INF/lib/";

180

}

181

182

@Override

183

public String getClassesLocation() {

184

return "WEB-INF/classes/";

185

}

186

187

@Override

188

public boolean isExecutable() {

189

return true;

190

}

191

}

192

}

193

```

194

195

### Layout Factory

196

197

Factory interface for creating layout instances based on source files.

198

199

```java { .api }

200

public interface LayoutFactory {

201

/**

202

* Create an appropriate layout for the given source file.

203

*

204

* @param source the source file to create a layout for

205

* @return the created layout

206

*/

207

Layout getLayout(File source);

208

}

209

210

public class DefaultLayoutFactory implements LayoutFactory {

211

/**

212

* Create a layout based on file extension and characteristics.

213

* - .jar files use Layouts.Jar

214

* - .war files use Layouts.War

215

* - Directories use Layouts.Expanded

216

*

217

* @param source the source file

218

* @return the appropriate layout

219

*/

220

@Override

221

public Layout getLayout(File source) {

222

// Implementation determines layout based on file type

223

}

224

}

225

```

226

227

## Usage Examples

228

229

### Basic Layout Selection

230

231

```java

232

import org.springframework.boot.loader.tools.Layout;

233

import org.springframework.boot.loader.tools.Layouts;

234

import java.io.File;

235

236

// Automatic layout selection

237

File jarFile = new File("myapp.jar");

238

Layout layout = Layouts.forFile(jarFile);

239

System.out.println("Launcher: " + layout.getLauncherClassName());

240

System.out.println("Classes location: " + layout.getClassesLocation());

241

System.out.println("Executable: " + layout.isExecutable());

242

243

// Output for JAR file:

244

// Launcher: org.springframework.boot.loader.launch.JarLauncher

245

// Classes location: BOOT-INF/classes/

246

// Executable: true

247

```

248

249

### Explicit Layout Configuration

250

251

```java

252

import org.springframework.boot.loader.tools.*;

253

import java.io.File;

254

255

// Use specific layout with repackager

256

File sourceJar = new File("myapp.jar");

257

Repackager repackager = new Repackager(sourceJar);

258

259

// Force WAR layout even for JAR file

260

Layout warLayout = new Layouts.War();

261

repackager.setLayout(warLayout);

262

263

// Libraries will be placed in WEB-INF/lib/ instead of BOOT-INF/lib/

264

repackager.repackage(Libraries.NONE);

265

```

266

267

### Custom Layout Implementation

268

269

```java

270

import org.springframework.boot.loader.tools.*;

271

272

// Create custom layout for special deployment requirements

273

public class CustomLayout implements RepackagingLayout {

274

@Override

275

public String getLauncherClassName() {

276

return "com.example.CustomLauncher";

277

}

278

279

@Override

280

public String getLibraryLocation(String libraryName, LibraryScope scope) {

281

// Separate compile and runtime dependencies

282

if (scope == LibraryScope.COMPILE) {

283

return "CUSTOM-INF/compile-lib/";

284

}

285

return "CUSTOM-INF/runtime-lib/";

286

}

287

288

@Override

289

public String getClassesLocation() {

290

return "CUSTOM-INF/app-classes/";

291

}

292

293

@Override

294

public String getRepackagedClassesLocation() {

295

return "CUSTOM-INF/app-classes/";

296

}

297

298

@Override

299

public boolean isExecutable() {

300

return true;

301

}

302

}

303

304

// Use custom layout

305

File sourceJar = new File("myapp.jar");

306

Repackager repackager = new Repackager(sourceJar);

307

repackager.setLayout(new CustomLayout());

308

repackager.repackage(Libraries.NONE);

309

```

310

311

### Layout Factory Usage

312

313

```java

314

import org.springframework.boot.loader.tools.*;

315

import java.io.File;

316

317

// Custom layout factory for special file types

318

public class CustomLayoutFactory implements LayoutFactory {

319

@Override

320

public Layout getLayout(File source) {

321

if (source.getName().endsWith(".ubar")) {

322

return new Layouts.War(); // Treat .ubar files as WAR

323

}

324

if (source.getName().contains("micro")) {

325

return new Layouts.Expanded(); // Use expanded layout for micro services

326

}

327

return Layouts.forFile(source); // Default behavior

328

}

329

}

330

331

// Configure repackager with custom factory

332

File sourceFile = new File("myapp.ubar");

333

Repackager repackager = new Repackager(sourceFile);

334

repackager.setLayoutFactory(new CustomLayoutFactory());

335

repackager.repackage(Libraries.NONE);

336

```

337

338

### Understanding Library Placement

339

340

```java

341

import org.springframework.boot.loader.tools.*;

342

import java.io.File;

343

344

// Examine how different layouts handle library placement

345

Layout jarLayout = new Layouts.Jar();

346

Layout warLayout = new Layouts.War();

347

348

String libName = "spring-core-5.3.21.jar";

349

350

// JAR layout

351

String jarLibLocation = jarLayout.getLibraryLocation(libName, LibraryScope.COMPILE);

352

System.out.println("JAR layout lib location: " + jarLibLocation);

353

// Output: BOOT-INF/lib/

354

355

// WAR layout with different scopes

356

String warCompileLocation = warLayout.getLibraryLocation(libName, LibraryScope.COMPILE);

357

String warProvidedLocation = warLayout.getLibraryLocation(libName, LibraryScope.PROVIDED);

358

System.out.println("WAR compile location: " + warCompileLocation);

359

System.out.println("WAR provided location: " + warProvidedLocation);

360

// Output: WEB-INF/lib/

361

// Output: WEB-INF/lib-provided/

362

```

363

364

### Custom Loader Layout

365

366

```java

367

import org.springframework.boot.loader.tools.*;

368

import java.io.IOException;

369

370

// Layout with custom loader classes

371

public class CustomLoaderLayout implements Layout, CustomLoaderLayout {

372

@Override

373

public String getLauncherClassName() {

374

return "com.example.CustomBootstrap";

375

}

376

377

@Override

378

public String getLibraryLocation(String libraryName, LibraryScope scope) {

379

return "META-INF/libs/";

380

}

381

382

@Override

383

public String getClassesLocation() {

384

return "META-INF/classes/";

385

}

386

387

@Override

388

public boolean isExecutable() {

389

return true;

390

}

391

392

@Override

393

public void writeLoadedClasses(LoaderClassesWriter writer) throws IOException {

394

// Write custom loader classes

395

try (var stream = getClass().getResourceAsStream("/custom-loader.jar")) {

396

writer.writeLoaderClasses("custom-loader.jar");

397

}

398

}

399

}

400

```

401

402

## Layout Decision Matrix

403

404

| File Type | Default Layout | Launcher Class | Classes Location | Libraries Location |

405

|-----------|----------------|----------------|-----------------|--------------------|

406

| .jar | Layouts.Jar | JarLauncher | BOOT-INF/classes/ | BOOT-INF/lib/ |

407

| .war | Layouts.War | WarLauncher | WEB-INF/classes/ | WEB-INF/lib/ |

408

| Directory | Layouts.Expanded | PropertiesLauncher | BOOT-INF/classes/ | BOOT-INF/lib/ |

409

| Other | Layouts.Jar | JarLauncher | BOOT-INF/classes/ | BOOT-INF/lib/ |

410

411

The layout system provides the foundation for Spring Boot's flexible packaging model, enabling different deployment strategies while maintaining consistent runtime behavior.