SlideShare una empresa de Scribd logo
1 de 76
© 2016, iText Group NV© 2016, iText Group NV
Oops, I broke my API
Bruno Lowagie & Raf Hens: iText @ JavaOne 2016
@bruno1970 – @rafhens – @iText
© 2016, iText Group NV
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText2
Agenda: five important questions
Who? Who are we and how did we break our API
What? What does it mean when people say they broke their API
Why? What are acceptable reasons to break an API
How? Or rather: how not to break your API
When? When to break the API, once the decision is made to do it
© 2016, iText Group NV© 2015, iText Group NV
Who?
 Who are we?
 What inspired us to present this talk?
 What do we want to achieve?
© 2016, iText Group NV
Bruno Lowagie
Original developer of iText
ex-CEO, current CTO at iText Group
Raf Hens
Director of Engineering at iText Group
Project lead of iText 7
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText4
Who are we?
© 2016, iText Group NV
What is iText?
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText5
iText is an open source library
for creating, processing, and
manipulating PDF files in Java
and .NET.
© 2016, iText Group NV
We broke our API (more than once)
2000: iText 0.30; first release (LGPL, later MPL/LGPL)
• 2003: iText 1.00
• 2007: iText 2.0.0
• 2009: iText 2.1.7; last version available under MPL/LGPL
2009: iText 5.0.0; API deliberately broken (switch to AGPL)
• 2012: iText 5.2.0; broken release (undeliberate)
• 2013: iText 5.3.x; deliberate API change for digital signature functionality
• 2016: iText 5.5.9; last “backward compatible” version
2016: iText 7; rewritten from scratch, not backward compatible
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText6
© 2016, iText Group NV
We’re not alone
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText7
In this talk, we want to share our
experience so that other
developers can avoid making the
mistakes we made. We’ll also
show other examples of APIs that
were broken and explain what we
learned from those examples
© 2016, iText Group NV© 2015, iText Group NV
What?
 What does “breaking an API” actually mean?
 Binary compatibility
 Source code compatibility
 Behavioral compatibility
© 2016, iText Group NV
Backwards compatibility
What is it?
• Java: original specification still 100% valid
• PDF: PDF 1.0 should still render 100% correctly
Examples of backwards compatibility
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText9
© 2016, iText Group NV
Three types of compatibility
• a certain type of compiled file can run on both systems (whether it be
hardware or software) without any changes
Binary compatibility
• the input file must be recompiled for every system, but does not need to be
changed before compiling.
Source code compatibility
• the behavior when processing the input file is the same
Behavioral compatibility
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText10
© 2016, iText Group NV© 2015, iText Group NV
Why?
 What are acceptable reasons to break an API?
 Why did we break our API?
© 2016, iText Group NV
Involuntary API breaks
• Customized version of Bouncy Castle in Android
• Renamed version “Spongy Castle” to work around this issue
Bouncy Castle
• A third party created a fork: iText 4
• The official iText groupID was used (which is not allowed)
• This broke many Maven builds
iText
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText12
© 2016, iText Group NV
Avoid breaking the API when possible
Use internal re-implementations
Use two methods for the same function
Deprecate old methods
Redundancy!
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText13
© 2016, iText Group NV
Redundancy can get painful
Rationale for deprecating XFA
Rationale for Python 3
• HTMLWorker / XML Worker / …
• Rendering APIs iText 5 / iText 7
Rationale for iText 7
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText14
© 2016, iText Group NV
In response to advancing technology
• Example: PDF
Standards and specifications change
• Hashing and encryption algorithms
• Impact on digital signatures
Processing power increases
• ASCII isn’t sufficient anymore, we need Unicode
Internationalization
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText15
© 2016, iText Group NV
Changing the API as a strategy
• Old games don’t work on new consoles
PlayStation, Xbox
• Reduce server load
• Reduce abuse
Twitter API change 2013
• Replace competing add-on with own add-on
SharePoint 2013
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText16
© 2016, iText Group NV
Why we changed the iText design
• The core design hadn’t changed since 2000
• Organic growth; many different contributors
• The world has changed since 2000
iText 7 versus iText 5
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText17
© 2016, iText Group NV© 2015, iText Group NV
How?
 What should you do to limit the damage?
 What should you avoid?
© 2016, iText Group NV
Use semantic versioning
Use an x.y.z notation
• The major version number (x):
• for breaking changes
• The minor version number (y):
• for new, yet backwards
compatible, features
• The patch version number (z):
• for updates which fix bugs
How not to do it:
• BouncyCastle
• PHP
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText19
© 2016, iText Group NV
A good design to start with is key
Spring 2 and Spring 3
• The original design
was future-proof
Python 2 and Python 3
• It took 4 years to
build Python 3
(2004-2008)
• Adoption of Python 3
was extremely slow
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText20
© 2016, iText Group NV
Avoid being a moving target
• Switch from Java 5 to Java 7
• without changing the version (1.0.0-SNAPSHOT)
Commons-imaging
• No leadership: breaking changes in minor versions
PHP
• Developed internally until API was more or less stable
iText 7
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText21
© 2016, iText Group NV
Use tools to detect breaking changes
Clirr: http://clirr.sourceforge.net/
Maven plugin (mvn clirr:check)
 We run it in a separate profile
SonarQube plugin
 Tip: create a separate SQ dashboard
JDiff: http://javadiff.sourceforge.net/
Javadoc doclet
Generates HTML report of API differences
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText22
© 2016, iText Group NV
Ease the pain
• iText: tutorials on Leanpub
Provide good documentation
• Python: tools
• Microsoft Word: document format conversion
Provide conversion tools
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText23
© 2016, iText Group NV
Avoid back-porting
• Disadvantages of back-porting
Python 3
• No new functionality in iText 5 (e.g. PDF 2.0)
iText 7
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText24
© 2016, iText Group NV
Have a clear EOL strategy
Python 2
procrastination
• Constantly
changing EOL date
iText
• iText 5: December
31, 2018
• iText 7: December
31, 2025
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText25
© 2016, iText Group NV© 2015, iText Group NV
When?
 Which conditions should be met before breaking the API?
 When is it acceptable to make a release that breaks the API?
© 2016, iText Group NV
It’s marketing’s fault
Product is announced
before it’s ready
• Example: the Universal
Windows Platform
Result: confusion
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText27
?!
© 2016, iText Group NV
It’s the sales’ fault
Want to sell an
upgrade NOW
Pushing to release
new versions
Don’t want to
lose business
Putting on hold
communication about
new versions to keep
current business old
version
Result:
confusion
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText28
© 2016, iText Group NV
In any case…
• Deprecate before you remove a class or a method
• Warn when code is subject to change
Don’t let it happen unnoticed
• A license change also breaks the API
Beware of non-technical changes
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText29
© 2016, iText Group NV© 2015, iText Group NV
Use case: iText 7
 New insights
 Lessons Learned
© 2016, iText Group NV
Making development future-proof
New insights that led to a complete
rewrite of iText 7
Make it modular, make
it extensible
Remove functional
overlap to avoid
maintenance hell
Meet customer
requests, e.g. special
writing systems
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText31
© 2016, iText Group NV
Big bang release or early release?
Big bang: what if we got it wrong?
Early release: heavy burden on support
• Release early for selected users
• Release as open source
• As soon as the API is stable
• Before the work is completely done
Something in-between:
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText32
© 2016, iText Group NV© 2015, iText Group NV
Questions?
© 2016, iText Group NV
Hello World: iText 5
public void createPdf(String dest)
throws DocumentException, IOException {
Document document = new Document();
PdfWriter.getInstance(
document, new FileOutputStream(dest));
document.open();
document.add(new Paragraph("Hello World!"));
document.close();
}
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText34
© 2016, iText Group NV
Hello World: iText 7 (example 1)
public void createPdf(String dest)
throws IOException {
PdfDocument pdf =
new PdfDocument(new PdfWriter(dest));
Document document = new Document(pdf);
document.add(new Paragraph("Hello World!"));
document.close();
}
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText35
© 2016, iText Group NV
Hello World: iText 7 (example 2)
public void createPdf(String dest)
throws IOException {
PdfDocument pdf =
new PdfDocument(new PdfWriter(dest));
try (Document document = new Document(pdf)) {
document.add(new Paragraph("Hello World!"));
}
}
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText36
© 2016, iText Group NV
Hello World: iText 5 vs iText 7
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText37
© 2016, iText Group NV
Fonts: iText 5
Font font = new Font(FontFamily.TIMES_ROMAN);
Font font14pt = new Font(FontFamily.TIMES_ROMAN, 14);
Font font10pt = new Font(FontFamily.TIMES_ROMAN, 10);
BaseFont bf_russian = BaseFont.createFont(
"resources/fonts/FreeSans.ttf",
"CP1251",
BaseFont.EMBEDDED);
Font russian = new Font(bf_russian, 12);
BaseFont bf_cjk = BaseFont.createFont(
"resources/fonts/NotoSansCJKsc-Regular.otf",
BaseFont.IDENTITY_H,
BaseFont.EMBEDDED);
Font cjk = new Font(bf_cjk, 12);
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText38
© 2016, iText Group NV
Fonts: iText 7
PdfFont font = PdfFontFactory.createFont(FontConstants.TIMES_ROMAN);
PdfFont russian = PdfFontFactory.createFont(
"src/main/resources/fonts/FreeSans.ttf",
"CP1251",
true);
PdfFont cjk = PdfFontFactory.createFont(
"src/main/resources/fonts/NotoSansCJKsc-Regular.otf",
PdfEncodings.IDENTITY_H,
true);
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText39
© 2016, iText Group NV
Fonts: iText 5
Paragraph p = new Paragraph("Hello World! ", font);
Chunk chunk = new Chunk("Hallo Wereld! ", font14pt);
p.add(chunk);
chunk = new Chunk("Bonjour le monde! ", font10pt);
chunk.setTextRise(4);
p.add(chunk);
chunk = new Chunk("u0417u0434 ... u0440! ", russian);
p.add(chunk);
p.add(new Chunk("u4f60u597du4e16u754c! ", cjk));
p.add(new Chunk("uc5ecubcf4 ... uacc4!", cjk));
document.add(p);
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText40
© 2016, iText Group NV
Fonts: iText 7
document.setFont(font);
Paragraph p = new Paragraph("Hello World! ")
.add(new Text("Hallo Wereld! ")
.setFontSize(14))
.add(
new Text("Bonjour le monde! ")
.setFontSize(10)
.setTextRise(4))
.add(
new Text ("u0417u0434 ... u0440! “).setFont(russian))
.add(
new Text("u4f60u597du4e16u754c! ").setFont(cjk))
.add(
new Text("uc5ecubcf4 ... uacc4!").setFont(cjk));
document.add(p);
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText41
© 2016, iText Group NV
Fonts: iText 5 vs iText 7
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText42
© 2016, iText Group NV
Switching styles: iText 5
public Chunk createBgChunk(String s, Font font) {
Chunk chunk = new Chunk(s, font);
chunk.setBackground(BaseColor.LIGHT_GRAY);
return chunk;
}
Font code = new Font(
FontFamily.COURIER, 12, Font.NORMAL, BaseColor.RED);
Paragraph p = new Paragraph("In this example, named ");
p.add(createBgChunk("HelloWorldStyles", code));
p.add(", we experiment with some text in ");
p.add(createBgChunk("code style", code));
p.add(".");
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText43
© 2016, iText Group NV
Switching styles: iText 7
Style style = new Style()
.setFont(code)
.setFontSize(12)
.setFontColor(Color.RED)
.setBackgroundColor(Color.LIGHT_GRAY);
document.add(
new Paragraph()
.add("In this example, named ")
.add(new Text("HelloWorldStyles").addStyle(style))
.add(", we experiment with some text in ")
.add(new Text("code style").addStyle(style))
.add("."));
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText44
© 2016, iText Group NV
Switching styles: iText 5 vs iText 7
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText45
© 2016, iText Group NV
Tables: iText 5
PdfPTable table = new PdfPTable(3);
PdfPCell cell = new PdfPCell(new Phrase("Cell with colspan 3"));
cell.setColspan(3);
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
table.addCell(cell);
cell = new PdfPCell(new Phrase("Cell with rowspan 2"));
cell.setRowspan(2);
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
table.addCell(cell);
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText46
© 2016, iText Group NV
Tables: iText 5
// text mode
table.addCell("Cell 1.1");
// composite mode
cell = new PdfPCell();
cell.addElement(new Phrase("Cell 1.2"));
table.addCell(cell);
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText47
© 2016, iText Group NV
Tables: iText 5
cell = new PdfPCell(new Phrase("Cell 2.1"));
cell.setPadding(5);
cell.setUseAscender(true);
cell.setUseDescender(true);
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
table.addCell(cell);
cell = new PdfPCell();
cell.setPadding(5);
cell.setUseAscender(true);
cell.setUseDescender(true);
Paragraph p = new Paragraph("Cell 2.2");
p.setAlignment(Element.ALIGN_CENTER);
cell.addElement(p);
table.addCell(cell);
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText48
© 2016, iText Group NV
Tables: iText 7
Table table = new Table(3);
Cell cell = new Cell(1, 3)
.setTextAlignment(TextAlignment.CENTER)
.add("Cell with colspan 3");
table.addCell(cell);
cell = new Cell(2, 1)
.add("Cell with rowspan 2")
.setVerticalAlignment(VerticalAlignment.MIDDLE);
table.addCell(cell);
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText49
© 2016, iText Group NV
Tables: iText 7
table.addCell("Cell 1.1");
table.addCell(new Cell().add("Cell 1.2"));
table.addCell(new Cell()
.add("Cell 2.1")
.setBackgroundColor(Color.LIGHT_GRAY)
.setMargin(5));
table.addCell(new Cell()
.add("Cell 1.2")
.setBackgroundColor(Color.LIGHT_GRAY)
.setPadding(5));
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText50
© 2016, iText Group NV
Tables: iText 5 vs iText 7
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText51
© 2016, iText Group NV
TXT 2 PDF: iText 5
Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream(dest));
document.open();
BufferedReader br = new BufferedReader(new FileReader(TEXT));
String line;
Paragraph p;
Font normal = new Font(FontFamily.TIMES_ROMAN, 12);
Font bold = new Font(FontFamily.TIMES_ROMAN, 12, Font.BOLD);
boolean title = true;
while ((line = br.readLine()) != null) {
p = new Paragraph(line, title ? bold : normal);
p.setAlignment(Element.ALIGN_JUSTIFIED);
title = line.isEmpty();
document.add(p);
}
document.close();
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText52
© 2016, iText Group NV
TXT 2 PDF: iText 7
PdfDocument pdf = new PdfDocument(new PdfWriter(dest));
Document document = new Document(pdf)
.setTextAlignment(TextAlignment.JUSTIFIED);
BufferedReader br = new BufferedReader(new FileReader(TEXT));
String line;
PdfFont normal = PdfFontFactory.createFont(FontConstants.TIMES_ROMAN);
PdfFont bold = PdfFontFactory.createFont(FontConstants.TIMES_BOLD);
boolean title = true;
while ((line = br.readLine()) != null) {
document.add(new Paragraph(line).setFont(title ? bold : normal));
title = line.isEmpty();
}
document.close();
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText53
© 2016, iText Group NV
TXT 2 PDF: iText 5 vs iText 7
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText54
© 2016, iText Group NV
Columns: iText 5
Document document = new Document();
PdfWriter writer =
PdfWriter.getInstance(document, new FileOutputStream(dest));
document.open();
ColumnText ct = new ColumnText(writer.getDirectContent());
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText55
© 2016, iText Group NV
Columns: iText 5
BufferedReader br = new BufferedReader(new FileReader(TEXT));
String line;
Paragraph p;
Font normal = new Font(FontFamily.TIMES_ROMAN, 12);
Font bold = new Font(FontFamily.TIMES_ROMAN, 12, Font.BOLD);
boolean title = true;
while ((line = br.readLine()) != null) {
p = new Paragraph(line, title ? bold : normal);
p.setAlignment(Element.ALIGN_JUSTIFIED);
title = line.isEmpty();
ct.addElement(p);
}
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText56
© 2016, iText Group NV
Columns: iText 5
Rectangle[] columns = {
new Rectangle(36, 36, 290, 806), new Rectangle(305, 36, 559, 806) }
int c = 0;
int status = ColumnText.START_COLUMN;
while (ColumnText.hasMoreText(status)) {
ct.setSimpleColumn(columns[c]);
status = ct.go();
if (++c == 2) {
document.newPage();
c = 0;
}
}
document.close();
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText57
© 2016, iText Group NV
Columns: iText 7
PdfDocument pdf = new PdfDocument(new PdfWriter(dest));
Document document = new Document(pdf)
.setTextAlignment(TextAlignment.JUSTIFIED);
Rectangle[] columns = {
new Rectangle(36, 36, 254, 770), new Rectangle(305, 36, 254, 770) };
document.setRenderer(new ColumnDocumentRenderer(document, columns));
BufferedReader br = new BufferedReader(new FileReader(TEXT));
String line;
PdfFont normal = PdfFontFactory.createFont(FontConstants.TIMES_ROMAN);
PdfFont bold = PdfFontFactory.createFont(FontConstants.TIMES_BOLD);
boolean title = true;
while ((line = br.readLine()) != null) {
document.add(new Paragraph(line).setFont(title ? bold : normal));
title = line.isEmpty();
}
document.close();
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText58
© 2016, iText Group NV
Columns: iText 5 vs iText 7
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText59
© 2016, iText Group NV
Page events: iText 5
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, new
FileOutputStream(dest));
MyPageEvents events = new MyPageEvents();
writer.setPageEvent(events);
document.open();
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText60
© 2016, iText Group NV
Page events: iText 5
BufferedReader br = new BufferedReader(new FileReader(TEXT));
String line;
Paragraph p;
Font normal = new Font(FontFamily.TIMES_ROMAN, 12);
Font bold = new Font(FontFamily.TIMES_ROMAN, 12, Font.BOLD);
boolean title = true;
while ((line = br.readLine()) != null) {
p = new Paragraph(line, title ? bold : normal);
p.setAlignment(Element.ALIGN_JUSTIFIED);
events.setTitle(title);
document.add(p);
title = line.isEmpty();
}
document.close();
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText61
© 2016, iText Group NV
Page events: iText 5
class MyPageEvents extends PdfPageEventHelper {
protected float startpos = -1;
protected boolean title = true;
public void setTitle(boolean title) {
this.title = title;
}
@Override
public void onEndPage(PdfWriter writer, Document document) { ... }
@Override
public void onParagraph(PdfWriter writer, Document document,
float paragraphPosition) { ... }
@Override
public void onParagraphEnd(PdfWriter writer, Document document,
float paragraphPosition) { ... }
}
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText62
© 2016, iText Group NV
Page events: iText 5
@Override
public void onEndPage(PdfWriter writer, Document document) {
Rectangle pagesize = document.getPageSize();
ColumnText.showTextAligned(
writer.getDirectContent(),
Element.ALIGN_CENTER,
new Phrase(String.valueOf(writer.getPageNumber())),
(pagesize.getLeft() + pagesize.getRight()) / 2,
pagesize.getBottom() + 15, 0);
if (startpos != -1)
onParagraphEnd(writer, document,
pagesize.getBottom(document.bottomMargin()));
startpos = pagesize.getTop(document.topMargin());
}
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText63
© 2016, iText Group NV
Page events: iText 5
@Override
public void onParagraph(PdfWriter writer, Document document, float paragraphPosition) {
startpos = paragraphPosition;
}
@Override
public void onParagraphEnd(PdfWriter writer, Document document, float paragraphPosition) {
if (!title) return;
PdfContentByte canvas = writer.getDirectContentUnder();
Rectangle pagesize = document.getPageSize();
canvas.saveState();
canvas.setColorStroke(BaseColor.BLUE);
canvas.rectangle(
pagesize.getLeft(document.leftMargin()),
paragraphPosition - 3,
pagesize.getWidth() - document.leftMargin() - document.rightMargin(),
startpos - paragraphPosition);
canvas.stroke();
canvas.restoreState();
}
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText64
© 2016, iText Group NV
Event handlers: iText 7
PdfDocument pdf = new PdfDocument(new PdfWriter(dest));
pdf.addEventHandler(PdfDocumentEvent.END_PAGE, new Footer());
Document document = new Document(pdf).setTextAlignment(TextAlignment.JUSTIFIED);
BufferedReader br = new BufferedReader(new FileReader(TEXT));
String line;
PdfFont normal = PdfFontFactory.createFont(FontConstants.TIMES_ROMAN);
PdfFont bold = PdfFontFactory.createFont(FontConstants.TIMES_BOLD);
boolean title = true;
Border border = new SolidBorder(Color.BLUE, 1);
while ((line = br.readLine()) != null) {
document.add(new Paragraph(line)
.setFont(title ? bold : normal)
.setBorder(title ? border : Border.NO_BORDER));
title = line.isEmpty();
}
document.close();
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText65
© 2016, iText Group NV
Event handlers: iText 7
protected class Footer implements IEventHandler {
@Override
public void handleEvent(Event event) {
PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
PdfDocument pdf = docEvent.getDocument();
PdfPage page = docEvent.getPage();
Rectangle pageSize = page.getPageSize();
PdfCanvas pdfCanvas = new PdfCanvas(
page.getLastContentStream(), page.getResources(), pdf);
Canvas canvas = new Canvas(pdfCanvas, pdf, pageSize);
float x = (pageSize.getLeft() + pageSize.getRight()) / 2;
float y = pageSize.getBottom() + 15;
canvas.showTextAligned(
String.valueOf(pdf.getPageNumber(page)),
x, y, TextAlignment.CENTER);
}
}
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText66
© 2016, iText Group NV
Events: iText 5 vs iText 7
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText67
© 2016, iText Group NV
Renderers: iText 7
public class TitleParagraph extends Paragraph {
public TitleParagraph(String line) {
super(line);
try { setFont(PdfFontFactory.createFont(FontConstants.TIMES_BOLD));
}
catch (IOException ioe) { }
}
@Override
protected IRenderer makeNewRenderer() {
return new ParagraphRenderer(this) {
...
};
}
}
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText68
© 2016, iText Group NV
Renderers: iText 7
@Override
public void drawBorder(DrawContext drawContext) {
Rectangle occupiedAreaBBox = getOccupiedAreaBBox();
float[] margins = getMargins();
Rectangle rectangle = applyMargins(occupiedAreaBBox, margins, false);
PdfCanvas canvas = drawContext.getCanvas();
canvas.roundRectangle(rectangle.getX() - 1, rectangle.getY() - 1,
rectangle.getWidth() + 2, rectangle.getHeight() + 2, 5).stroke();
}
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText69
© 2016, iText Group NV
Renderers: iText 5 vs iText 7
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText70
© 2016, iText Group NV
Form creation: iText 5
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
TextField tf = new TextField(stamper.getWriter(),
new Rectangle(110, 780, 180, 806), "text");
tf.setBorderColor(BaseColor.BLUE);
tf.setBorderWidth(2);
tf.setTextColor(BaseColor.RED);
tf.setFontSize(12);
tf.setText("Text field");
PdfFormField field = tf.getTextField();
stamper.addAnnotation(field, 1);
stamper.close();
reader.close();
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText71
© 2016, iText Group NV
Form creation: iText 7
PdfReader reader = new PdfReader(src);
PdfDocument pdf = new PdfDocument(reader, new PdfWriter(dest));
PdfAcroForm form = PdfAcroForm.getAcroForm(pdf, true);
PdfFormField tf = PdfTextFormField.createText(pdf,
new Rectangle(110, 780, 70, 26), "text", "Text Field")
.setBorderColor(Color.BLUE)
.setBorderWidth(2)
.setColor(Color.RED)
.setFontSize(12);
form.addField(tf);
pdf.close();
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText72
© 2016, iText Group NV
Form creation: iText 5 vs iText 7
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText73
© 2016, iText Group NV
Form filling: iText 5
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
AcroFields fields = stamper.getAcroFields();
fields.setFieldProperty("text", "textcolor", BaseColor.BLUE, null);
fields.setFieldProperty("text", "bordercolor", BaseColor.RED, null);
fields.setFieldProperty("text", "fontsize", 14, null);
fields.setField("text", "Field Text");
stamper.close();
reader.close();
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText74
© 2016, iText Group NV
Form filling: iText 7
PdfReader reader = new PdfReader(src);
PdfDocument pdf = new PdfDocument(reader, new PdfWriter(dest));
PdfAcroForm form = PdfAcroForm.getAcroForm(pdf, true);
PdfFormField tf = form.getFormFields().get("text");
tf.setBorderColor(Color.RED)
.setColor(Color.BLUE)
.setFontSize(14)
.setValue("Field Text");
pdf.close();
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText75
© 2016, iText Group NV
Form filling: iText 5 vs iText 7
Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText76

Más contenido relacionado

La actualidad más candente

LCA14: LCA14-502: The way to a generic TrustZone® solution
LCA14: LCA14-502: The way to a generic TrustZone® solutionLCA14: LCA14-502: The way to a generic TrustZone® solution
LCA14: LCA14-502: The way to a generic TrustZone® solutionLinaro
 
SpringOne Tour: Spring Boot 3 and Beyond
SpringOne Tour: Spring Boot 3 and BeyondSpringOne Tour: Spring Boot 3 and Beyond
SpringOne Tour: Spring Boot 3 and BeyondVMware Tanzu
 
Yocto - Embedded Linux Distribution Maker
Yocto - Embedded Linux Distribution MakerYocto - Embedded Linux Distribution Maker
Yocto - Embedded Linux Distribution MakerSherif Mousa
 
Secure boot general
Secure boot generalSecure boot general
Secure boot generalPrabhu Swamy
 
LAS16-111: Easing Access to ARM TrustZone – OP-TEE and Raspberry Pi 3
LAS16-111: Easing Access to ARM TrustZone – OP-TEE and Raspberry Pi 3LAS16-111: Easing Access to ARM TrustZone – OP-TEE and Raspberry Pi 3
LAS16-111: Easing Access to ARM TrustZone – OP-TEE and Raspberry Pi 3Linaro
 
Trusted firmware deep_dive_v1.0_
Trusted firmware deep_dive_v1.0_Trusted firmware deep_dive_v1.0_
Trusted firmware deep_dive_v1.0_Linaro
 
OWASP 2015 AppSec EU ZAP 2.4.0 and beyond..
OWASP 2015 AppSec EU ZAP 2.4.0 and beyond..OWASP 2015 AppSec EU ZAP 2.4.0 and beyond..
OWASP 2015 AppSec EU ZAP 2.4.0 and beyond..Simon Bennetts
 
Service Discovery using etcd, Consul and Kubernetes
Service Discovery using etcd, Consul and KubernetesService Discovery using etcd, Consul and Kubernetes
Service Discovery using etcd, Consul and KubernetesSreenivas Makam
 
How to Choose a Software Update Mechanism for Embedded Linux Devices
How to Choose a Software Update Mechanism for Embedded Linux DevicesHow to Choose a Software Update Mechanism for Embedded Linux Devices
How to Choose a Software Update Mechanism for Embedded Linux DevicesLeon Anavi
 
Gitlab flow solo
Gitlab flow soloGitlab flow solo
Gitlab flow soloviniciusban
 
A crash course in CRUSH
A crash course in CRUSHA crash course in CRUSH
A crash course in CRUSHSage Weil
 
Build your own embedded linux distributions by yocto project
Build your own embedded linux distributions by yocto projectBuild your own embedded linux distributions by yocto project
Build your own embedded linux distributions by yocto projectYen-Chin Lee
 
Kvm and libvirt
Kvm and libvirtKvm and libvirt
Kvm and libvirtplarsen67
 

La actualidad más candente (20)

Git & GitHub for Beginners
Git & GitHub for BeginnersGit & GitHub for Beginners
Git & GitHub for Beginners
 
Building aosp
Building aospBuilding aosp
Building aosp
 
Svn Basic Tutorial
Svn Basic TutorialSvn Basic Tutorial
Svn Basic Tutorial
 
LCA14: LCA14-502: The way to a generic TrustZone® solution
LCA14: LCA14-502: The way to a generic TrustZone® solutionLCA14: LCA14-502: The way to a generic TrustZone® solution
LCA14: LCA14-502: The way to a generic TrustZone® solution
 
SpringOne Tour: Spring Boot 3 and Beyond
SpringOne Tour: Spring Boot 3 and BeyondSpringOne Tour: Spring Boot 3 and Beyond
SpringOne Tour: Spring Boot 3 and Beyond
 
Yocto - Embedded Linux Distribution Maker
Yocto - Embedded Linux Distribution MakerYocto - Embedded Linux Distribution Maker
Yocto - Embedded Linux Distribution Maker
 
Secure boot general
Secure boot generalSecure boot general
Secure boot general
 
LAS16-111: Easing Access to ARM TrustZone – OP-TEE and Raspberry Pi 3
LAS16-111: Easing Access to ARM TrustZone – OP-TEE and Raspberry Pi 3LAS16-111: Easing Access to ARM TrustZone – OP-TEE and Raspberry Pi 3
LAS16-111: Easing Access to ARM TrustZone – OP-TEE and Raspberry Pi 3
 
Trusted firmware deep_dive_v1.0_
Trusted firmware deep_dive_v1.0_Trusted firmware deep_dive_v1.0_
Trusted firmware deep_dive_v1.0_
 
OWASP 2015 AppSec EU ZAP 2.4.0 and beyond..
OWASP 2015 AppSec EU ZAP 2.4.0 and beyond..OWASP 2015 AppSec EU ZAP 2.4.0 and beyond..
OWASP 2015 AppSec EU ZAP 2.4.0 and beyond..
 
Service Discovery using etcd, Consul and Kubernetes
Service Discovery using etcd, Consul and KubernetesService Discovery using etcd, Consul and Kubernetes
Service Discovery using etcd, Consul and Kubernetes
 
Linux Kernel I/O Schedulers
Linux Kernel I/O SchedulersLinux Kernel I/O Schedulers
Linux Kernel I/O Schedulers
 
Github in Action
Github in ActionGithub in Action
Github in Action
 
How to Choose a Software Update Mechanism for Embedded Linux Devices
How to Choose a Software Update Mechanism for Embedded Linux DevicesHow to Choose a Software Update Mechanism for Embedded Linux Devices
How to Choose a Software Update Mechanism for Embedded Linux Devices
 
Gitlab flow solo
Gitlab flow soloGitlab flow solo
Gitlab flow solo
 
A crash course in CRUSH
A crash course in CRUSHA crash course in CRUSH
A crash course in CRUSH
 
Terraform
TerraformTerraform
Terraform
 
Build your own embedded linux distributions by yocto project
Build your own embedded linux distributions by yocto projectBuild your own embedded linux distributions by yocto project
Build your own embedded linux distributions by yocto project
 
spinlock.pdf
spinlock.pdfspinlock.pdf
spinlock.pdf
 
Kvm and libvirt
Kvm and libvirtKvm and libvirt
Kvm and libvirt
 

Destacado

Intellectual property and licensing
Intellectual property and licensingIntellectual property and licensing
Intellectual property and licensingiText Group nv
 
PDF made easy with iText 7
PDF made easy with iText 7PDF made easy with iText 7
PDF made easy with iText 7iText Group nv
 
FIT Seminar Singapore presentation
FIT Seminar Singapore presentationFIT Seminar Singapore presentation
FIT Seminar Singapore presentationiText Group nv
 
Monetizing open-source projects
Monetizing open-source projectsMonetizing open-source projects
Monetizing open-source projectsiText Group nv
 
Tech Startup Day 2015: 4 failures and 1 hit
Tech Startup Day 2015: 4 failures and 1 hitTech Startup Day 2015: 4 failures and 1 hit
Tech Startup Day 2015: 4 failures and 1 hitiText Group nv
 
Start-ups: the tortoise and the hare
Start-ups: the tortoise and the hareStart-ups: the tortoise and the hare
Start-ups: the tortoise and the hareiText Group nv
 
The importance of standards
The importance of standardsThe importance of standards
The importance of standardsiText Group nv
 
iText Summit 2014: Keynote talk
iText Summit 2014: Keynote talkiText Summit 2014: Keynote talk
iText Summit 2014: Keynote talkiText Group nv
 
Digital Signatures: how it's done in PDF
Digital Signatures: how it's done in PDFDigital Signatures: how it's done in PDF
Digital Signatures: how it's done in PDFiText Group nv
 
PAdES signatures in iText and the road ahead
PAdES signatures in iText and the road aheadPAdES signatures in iText and the road ahead
PAdES signatures in iText and the road aheadiText Group nv
 
Digital Signatures: how it's done in PDF
Digital Signatures: how it's done in PDFDigital Signatures: how it's done in PDF
Digital Signatures: how it's done in PDFiText Group nv
 

Destacado (12)

Intellectual property and licensing
Intellectual property and licensingIntellectual property and licensing
Intellectual property and licensing
 
PDF made easy with iText 7
PDF made easy with iText 7PDF made easy with iText 7
PDF made easy with iText 7
 
FIT Seminar Singapore presentation
FIT Seminar Singapore presentationFIT Seminar Singapore presentation
FIT Seminar Singapore presentation
 
Monetizing open-source projects
Monetizing open-source projectsMonetizing open-source projects
Monetizing open-source projects
 
Tech Startup Day 2015: 4 failures and 1 hit
Tech Startup Day 2015: 4 failures and 1 hitTech Startup Day 2015: 4 failures and 1 hit
Tech Startup Day 2015: 4 failures and 1 hit
 
Start-ups: the tortoise and the hare
Start-ups: the tortoise and the hareStart-ups: the tortoise and the hare
Start-ups: the tortoise and the hare
 
The importance of standards
The importance of standardsThe importance of standards
The importance of standards
 
iText Summit 2014: Keynote talk
iText Summit 2014: Keynote talkiText Summit 2014: Keynote talk
iText Summit 2014: Keynote talk
 
Digital Signatures: how it's done in PDF
Digital Signatures: how it's done in PDFDigital Signatures: how it's done in PDF
Digital Signatures: how it's done in PDF
 
PAdES signatures in iText and the road ahead
PAdES signatures in iText and the road aheadPAdES signatures in iText and the road ahead
PAdES signatures in iText and the road ahead
 
ZUGFeRD: an overview
ZUGFeRD: an overviewZUGFeRD: an overview
ZUGFeRD: an overview
 
Digital Signatures: how it's done in PDF
Digital Signatures: how it's done in PDFDigital Signatures: how it's done in PDF
Digital Signatures: how it's done in PDF
 

Similar a Oops, I broke my API

How can large open source projects be monetized?
How can large open source projects be monetized?How can large open source projects be monetized?
How can large open source projects be monetized?Bruno Lowagie
 
Building Your API for Longevity
Building Your API for LongevityBuilding Your API for Longevity
Building Your API for LongevityMuleSoft
 
Intro to Open source. Amit Bhayani
Intro to Open source. Amit BhayaniIntro to Open source. Amit Bhayani
Intro to Open source. Amit Bhayaniguest2a6108
 
How can large open source projects be monetized?
How can large open source projects be monetized?How can large open source projects be monetized?
How can large open source projects be monetized?Bruno Lowagie
 
APIdays 2016 - The State of Web API Languages
APIdays 2016  - The State of Web API LanguagesAPIdays 2016  - The State of Web API Languages
APIdays 2016 - The State of Web API LanguagesRestlet
 
BelTech 2017 - Building Quality in the Browser
BelTech 2017 - Building Quality in the BrowserBelTech 2017 - Building Quality in the Browser
BelTech 2017 - Building Quality in the BrowserEamonn Boyle
 
Bringing Pull Request to Gerrit
Bringing Pull Request to GerritBringing Pull Request to Gerrit
Bringing Pull Request to GerritEryk Szymanski
 
Simplifying the OpenAPI Development Experience
Simplifying the OpenAPI Development Experience Simplifying the OpenAPI Development Experience
Simplifying the OpenAPI Development Experience confluent
 
How to Port a 9 Million Code Line Project to 64 bits?
How to Port a 9 Million Code Line Project to 64 bits? How to Port a 9 Million Code Line Project to 64 bits?
How to Port a 9 Million Code Line Project to 64 bits? PVS-Studio
 
OpenAPI v.Next - Events, Alternative Schemas & the Road Ahead
OpenAPI v.Next - Events, Alternative Schemas & the Road AheadOpenAPI v.Next - Events, Alternative Schemas & the Road Ahead
OpenAPI v.Next - Events, Alternative Schemas & the Road AheadTed Epstein
 
API Contract as Code: Rapid Development with OpenAPI
API Contract as Code: Rapid Development with OpenAPIAPI Contract as Code: Rapid Development with OpenAPI
API Contract as Code: Rapid Development with OpenAPISmartBear
 
An Overview ASP.NET vNEXT - CRB Tech
An Overview ASP.NET vNEXT - CRB TechAn Overview ASP.NET vNEXT - CRB Tech
An Overview ASP.NET vNEXT - CRB TechPooja Gaikwad
 
Next generation asp.net v next
Next generation asp.net v nextNext generation asp.net v next
Next generation asp.net v nextsonia merchant
 
Implications and future of Conversation as a Platform (CaaP)
Implications and future of Conversation as a Platform (CaaP)Implications and future of Conversation as a Platform (CaaP)
Implications and future of Conversation as a Platform (CaaP)Holger Mueller
 
2007q4 Developer Roadmap
2007q4 Developer Roadmap2007q4 Developer Roadmap
2007q4 Developer RoadmapPhil Wolff
 
Overview of webSpoon @ Pentaho Community Meeting 2016 (PCM16)
Overview of webSpoon @ Pentaho Community Meeting 2016 (PCM16)Overview of webSpoon @ Pentaho Community Meeting 2016 (PCM16)
Overview of webSpoon @ Pentaho Community Meeting 2016 (PCM16)Hiromu Hota
 
API Design Best Practices by Igor Miniailo
API Design Best Practices by Igor MiniailoAPI Design Best Practices by Igor Miniailo
API Design Best Practices by Igor MiniailoMagecom UK Limited
 
NLU / Intent Detection Benchmark by Intento, August 2017
NLU / Intent Detection Benchmark by Intento, August 2017NLU / Intent Detection Benchmark by Intento, August 2017
NLU / Intent Detection Benchmark by Intento, August 2017Konstantin Savenkov
 

Similar a Oops, I broke my API (20)

How can large open source projects be monetized?
How can large open source projects be monetized?How can large open source projects be monetized?
How can large open source projects be monetized?
 
Building Your API for Longevity
Building Your API for LongevityBuilding Your API for Longevity
Building Your API for Longevity
 
Intro to Open source. Amit Bhayani
Intro to Open source. Amit BhayaniIntro to Open source. Amit Bhayani
Intro to Open source. Amit Bhayani
 
How can large open source projects be monetized?
How can large open source projects be monetized?How can large open source projects be monetized?
How can large open source projects be monetized?
 
APIdays 2016 - The State of Web API Languages
APIdays 2016  - The State of Web API LanguagesAPIdays 2016  - The State of Web API Languages
APIdays 2016 - The State of Web API Languages
 
BelTech 2017 - Building Quality in the Browser
BelTech 2017 - Building Quality in the BrowserBelTech 2017 - Building Quality in the Browser
BelTech 2017 - Building Quality in the Browser
 
Bringing Pull Request to Gerrit
Bringing Pull Request to GerritBringing Pull Request to Gerrit
Bringing Pull Request to Gerrit
 
Simplifying the OpenAPI Development Experience
Simplifying the OpenAPI Development Experience Simplifying the OpenAPI Development Experience
Simplifying the OpenAPI Development Experience
 
How to Port a 9 Million Code Line Project to 64 bits?
How to Port a 9 Million Code Line Project to 64 bits? How to Port a 9 Million Code Line Project to 64 bits?
How to Port a 9 Million Code Line Project to 64 bits?
 
OpenAPI v.Next - Events, Alternative Schemas & the Road Ahead
OpenAPI v.Next - Events, Alternative Schemas & the Road AheadOpenAPI v.Next - Events, Alternative Schemas & the Road Ahead
OpenAPI v.Next - Events, Alternative Schemas & the Road Ahead
 
API Contract as Code: Rapid Development with OpenAPI
API Contract as Code: Rapid Development with OpenAPIAPI Contract as Code: Rapid Development with OpenAPI
API Contract as Code: Rapid Development with OpenAPI
 
Cloud Foundry Summit 2017
Cloud Foundry Summit 2017Cloud Foundry Summit 2017
Cloud Foundry Summit 2017
 
An Overview ASP.NET vNEXT - CRB Tech
An Overview ASP.NET vNEXT - CRB TechAn Overview ASP.NET vNEXT - CRB Tech
An Overview ASP.NET vNEXT - CRB Tech
 
Next generation asp.net v next
Next generation asp.net v nextNext generation asp.net v next
Next generation asp.net v next
 
Implications and future of Conversation as a Platform (CaaP)
Implications and future of Conversation as a Platform (CaaP)Implications and future of Conversation as a Platform (CaaP)
Implications and future of Conversation as a Platform (CaaP)
 
2007q4 Developer Roadmap
2007q4 Developer Roadmap2007q4 Developer Roadmap
2007q4 Developer Roadmap
 
Overview of webSpoon @ Pentaho Community Meeting 2016 (PCM16)
Overview of webSpoon @ Pentaho Community Meeting 2016 (PCM16)Overview of webSpoon @ Pentaho Community Meeting 2016 (PCM16)
Overview of webSpoon @ Pentaho Community Meeting 2016 (PCM16)
 
API Design Best Practices by Igor Miniailo
API Design Best Practices by Igor MiniailoAPI Design Best Practices by Igor Miniailo
API Design Best Practices by Igor Miniailo
 
NLU / Intent Detection Benchmark by Intento, August 2017
NLU / Intent Detection Benchmark by Intento, August 2017NLU / Intent Detection Benchmark by Intento, August 2017
NLU / Intent Detection Benchmark by Intento, August 2017
 
Graphql
GraphqlGraphql
Graphql
 

Más de iText Group nv

The effects of the GDPR
The effects of the GDPRThe effects of the GDPR
The effects of the GDPRiText Group nv
 
Build your own_photobooth
Build your own_photoboothBuild your own_photobooth
Build your own_photoboothiText Group nv
 
ETDA Conference - Digital signatures: how it's done in PDF
ETDA Conference - Digital signatures: how it's done in PDFETDA Conference - Digital signatures: how it's done in PDF
ETDA Conference - Digital signatures: how it's done in PDFiText Group nv
 
IANAL: what developers should know about IP and Legal
IANAL: what developers should know about IP and LegalIANAL: what developers should know about IP and Legal
IANAL: what developers should know about IP and LegaliText Group nv
 
Digital Signatures in the Cloud: A B2C Case Study
Digital Signatures in the Cloud: A B2C Case StudyDigital Signatures in the Cloud: A B2C Case Study
Digital Signatures in the Cloud: A B2C Case StudyiText Group nv
 
PDF is dead. Long live PDF... with Java!
PDF is dead. Long live PDF... with Java!PDF is dead. Long live PDF... with Java!
PDF is dead. Long live PDF... with Java!iText Group nv
 
iText Summit 2014: Talk: iText throughout the document life cycle
iText Summit 2014: Talk: iText throughout the document life cycleiText Summit 2014: Talk: iText throughout the document life cycle
iText Summit 2014: Talk: iText throughout the document life cycleiText Group nv
 
iText Summit 2014: Talk: eGriffie and JustX, introducing digital documents at...
iText Summit 2014: Talk: eGriffie and JustX, introducing digital documents at...iText Summit 2014: Talk: eGriffie and JustX, introducing digital documents at...
iText Summit 2014: Talk: eGriffie and JustX, introducing digital documents at...iText Group nv
 
The XML Forms Architecture
The XML Forms ArchitectureThe XML Forms Architecture
The XML Forms ArchitectureiText Group nv
 
Damn, the new generation kids are getting iPads in Highschool!
Damn, the new generation kids are getting iPads in Highschool!Damn, the new generation kids are getting iPads in Highschool!
Damn, the new generation kids are getting iPads in Highschool!iText Group nv
 
Best practices in Certifying and Signing PDFs
Best practices in Certifying and Signing PDFsBest practices in Certifying and Signing PDFs
Best practices in Certifying and Signing PDFsiText Group nv
 
Choosing the iText Solution that is right for you: Community or Commercial ed...
Choosing the iText Solution that is right for you: Community or Commercial ed...Choosing the iText Solution that is right for you: Community or Commercial ed...
Choosing the iText Solution that is right for you: Community or Commercial ed...iText Group nv
 

Más de iText Group nv (12)

The effects of the GDPR
The effects of the GDPRThe effects of the GDPR
The effects of the GDPR
 
Build your own_photobooth
Build your own_photoboothBuild your own_photobooth
Build your own_photobooth
 
ETDA Conference - Digital signatures: how it's done in PDF
ETDA Conference - Digital signatures: how it's done in PDFETDA Conference - Digital signatures: how it's done in PDF
ETDA Conference - Digital signatures: how it's done in PDF
 
IANAL: what developers should know about IP and Legal
IANAL: what developers should know about IP and LegalIANAL: what developers should know about IP and Legal
IANAL: what developers should know about IP and Legal
 
Digital Signatures in the Cloud: A B2C Case Study
Digital Signatures in the Cloud: A B2C Case StudyDigital Signatures in the Cloud: A B2C Case Study
Digital Signatures in the Cloud: A B2C Case Study
 
PDF is dead. Long live PDF... with Java!
PDF is dead. Long live PDF... with Java!PDF is dead. Long live PDF... with Java!
PDF is dead. Long live PDF... with Java!
 
iText Summit 2014: Talk: iText throughout the document life cycle
iText Summit 2014: Talk: iText throughout the document life cycleiText Summit 2014: Talk: iText throughout the document life cycle
iText Summit 2014: Talk: iText throughout the document life cycle
 
iText Summit 2014: Talk: eGriffie and JustX, introducing digital documents at...
iText Summit 2014: Talk: eGriffie and JustX, introducing digital documents at...iText Summit 2014: Talk: eGriffie and JustX, introducing digital documents at...
iText Summit 2014: Talk: eGriffie and JustX, introducing digital documents at...
 
The XML Forms Architecture
The XML Forms ArchitectureThe XML Forms Architecture
The XML Forms Architecture
 
Damn, the new generation kids are getting iPads in Highschool!
Damn, the new generation kids are getting iPads in Highschool!Damn, the new generation kids are getting iPads in Highschool!
Damn, the new generation kids are getting iPads in Highschool!
 
Best practices in Certifying and Signing PDFs
Best practices in Certifying and Signing PDFsBest practices in Certifying and Signing PDFs
Best practices in Certifying and Signing PDFs
 
Choosing the iText Solution that is right for you: Community or Commercial ed...
Choosing the iText Solution that is right for you: Community or Commercial ed...Choosing the iText Solution that is right for you: Community or Commercial ed...
Choosing the iText Solution that is right for you: Community or Commercial ed...
 

Último

英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作qr0udbr0
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio, Inc.
 
Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Mater
 
How to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationHow to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationBradBedford3
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityNeo4j
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxTier1 app
 
Best Web Development Agency- Idiosys USA.pdf
Best Web Development Agency- Idiosys USA.pdfBest Web Development Agency- Idiosys USA.pdf
Best Web Development Agency- Idiosys USA.pdfIdiosysTechnologies1
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsAhmed Mohamed
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfFerryKemperman
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEOrtus Solutions, Corp
 
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Angel Borroy López
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Velvetech LLC
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaHanief Utama
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfAlina Yurenko
 
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanyChristoph Pohl
 
What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...Technogeeks
 
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...confluent
 
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...OnePlan Solutions
 

Último (20)

英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
 
Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)
 
How to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationHow to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion Application
 
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort ServiceHot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered Sustainability
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
 
Best Web Development Agency- Idiosys USA.pdf
Best Web Development Agency- Idiosys USA.pdfBest Web Development Agency- Idiosys USA.pdf
Best Web Development Agency- Idiosys USA.pdf
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML Diagrams
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdf
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
 
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief Utama
 
Advantages of Odoo ERP 17 for Your Business
Advantages of Odoo ERP 17 for Your BusinessAdvantages of Odoo ERP 17 for Your Business
Advantages of Odoo ERP 17 for Your Business
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
 
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
 
What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...
 
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
 
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
 

Oops, I broke my API

  • 1. © 2016, iText Group NV© 2016, iText Group NV Oops, I broke my API Bruno Lowagie & Raf Hens: iText @ JavaOne 2016 @bruno1970 – @rafhens – @iText
  • 2. © 2016, iText Group NV Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText2 Agenda: five important questions Who? Who are we and how did we break our API What? What does it mean when people say they broke their API Why? What are acceptable reasons to break an API How? Or rather: how not to break your API When? When to break the API, once the decision is made to do it
  • 3. © 2016, iText Group NV© 2015, iText Group NV Who?  Who are we?  What inspired us to present this talk?  What do we want to achieve?
  • 4. © 2016, iText Group NV Bruno Lowagie Original developer of iText ex-CEO, current CTO at iText Group Raf Hens Director of Engineering at iText Group Project lead of iText 7 Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText4 Who are we?
  • 5. © 2016, iText Group NV What is iText? Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText5 iText is an open source library for creating, processing, and manipulating PDF files in Java and .NET.
  • 6. © 2016, iText Group NV We broke our API (more than once) 2000: iText 0.30; first release (LGPL, later MPL/LGPL) • 2003: iText 1.00 • 2007: iText 2.0.0 • 2009: iText 2.1.7; last version available under MPL/LGPL 2009: iText 5.0.0; API deliberately broken (switch to AGPL) • 2012: iText 5.2.0; broken release (undeliberate) • 2013: iText 5.3.x; deliberate API change for digital signature functionality • 2016: iText 5.5.9; last “backward compatible” version 2016: iText 7; rewritten from scratch, not backward compatible Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText6
  • 7. © 2016, iText Group NV We’re not alone Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText7 In this talk, we want to share our experience so that other developers can avoid making the mistakes we made. We’ll also show other examples of APIs that were broken and explain what we learned from those examples
  • 8. © 2016, iText Group NV© 2015, iText Group NV What?  What does “breaking an API” actually mean?  Binary compatibility  Source code compatibility  Behavioral compatibility
  • 9. © 2016, iText Group NV Backwards compatibility What is it? • Java: original specification still 100% valid • PDF: PDF 1.0 should still render 100% correctly Examples of backwards compatibility Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText9
  • 10. © 2016, iText Group NV Three types of compatibility • a certain type of compiled file can run on both systems (whether it be hardware or software) without any changes Binary compatibility • the input file must be recompiled for every system, but does not need to be changed before compiling. Source code compatibility • the behavior when processing the input file is the same Behavioral compatibility Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText10
  • 11. © 2016, iText Group NV© 2015, iText Group NV Why?  What are acceptable reasons to break an API?  Why did we break our API?
  • 12. © 2016, iText Group NV Involuntary API breaks • Customized version of Bouncy Castle in Android • Renamed version “Spongy Castle” to work around this issue Bouncy Castle • A third party created a fork: iText 4 • The official iText groupID was used (which is not allowed) • This broke many Maven builds iText Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText12
  • 13. © 2016, iText Group NV Avoid breaking the API when possible Use internal re-implementations Use two methods for the same function Deprecate old methods Redundancy! Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText13
  • 14. © 2016, iText Group NV Redundancy can get painful Rationale for deprecating XFA Rationale for Python 3 • HTMLWorker / XML Worker / … • Rendering APIs iText 5 / iText 7 Rationale for iText 7 Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText14
  • 15. © 2016, iText Group NV In response to advancing technology • Example: PDF Standards and specifications change • Hashing and encryption algorithms • Impact on digital signatures Processing power increases • ASCII isn’t sufficient anymore, we need Unicode Internationalization Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText15
  • 16. © 2016, iText Group NV Changing the API as a strategy • Old games don’t work on new consoles PlayStation, Xbox • Reduce server load • Reduce abuse Twitter API change 2013 • Replace competing add-on with own add-on SharePoint 2013 Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText16
  • 17. © 2016, iText Group NV Why we changed the iText design • The core design hadn’t changed since 2000 • Organic growth; many different contributors • The world has changed since 2000 iText 7 versus iText 5 Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText17
  • 18. © 2016, iText Group NV© 2015, iText Group NV How?  What should you do to limit the damage?  What should you avoid?
  • 19. © 2016, iText Group NV Use semantic versioning Use an x.y.z notation • The major version number (x): • for breaking changes • The minor version number (y): • for new, yet backwards compatible, features • The patch version number (z): • for updates which fix bugs How not to do it: • BouncyCastle • PHP Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText19
  • 20. © 2016, iText Group NV A good design to start with is key Spring 2 and Spring 3 • The original design was future-proof Python 2 and Python 3 • It took 4 years to build Python 3 (2004-2008) • Adoption of Python 3 was extremely slow Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText20
  • 21. © 2016, iText Group NV Avoid being a moving target • Switch from Java 5 to Java 7 • without changing the version (1.0.0-SNAPSHOT) Commons-imaging • No leadership: breaking changes in minor versions PHP • Developed internally until API was more or less stable iText 7 Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText21
  • 22. © 2016, iText Group NV Use tools to detect breaking changes Clirr: http://clirr.sourceforge.net/ Maven plugin (mvn clirr:check)  We run it in a separate profile SonarQube plugin  Tip: create a separate SQ dashboard JDiff: http://javadiff.sourceforge.net/ Javadoc doclet Generates HTML report of API differences Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText22
  • 23. © 2016, iText Group NV Ease the pain • iText: tutorials on Leanpub Provide good documentation • Python: tools • Microsoft Word: document format conversion Provide conversion tools Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText23
  • 24. © 2016, iText Group NV Avoid back-porting • Disadvantages of back-porting Python 3 • No new functionality in iText 5 (e.g. PDF 2.0) iText 7 Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText24
  • 25. © 2016, iText Group NV Have a clear EOL strategy Python 2 procrastination • Constantly changing EOL date iText • iText 5: December 31, 2018 • iText 7: December 31, 2025 Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText25
  • 26. © 2016, iText Group NV© 2015, iText Group NV When?  Which conditions should be met before breaking the API?  When is it acceptable to make a release that breaks the API?
  • 27. © 2016, iText Group NV It’s marketing’s fault Product is announced before it’s ready • Example: the Universal Windows Platform Result: confusion Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText27 ?!
  • 28. © 2016, iText Group NV It’s the sales’ fault Want to sell an upgrade NOW Pushing to release new versions Don’t want to lose business Putting on hold communication about new versions to keep current business old version Result: confusion Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText28
  • 29. © 2016, iText Group NV In any case… • Deprecate before you remove a class or a method • Warn when code is subject to change Don’t let it happen unnoticed • A license change also breaks the API Beware of non-technical changes Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText29
  • 30. © 2016, iText Group NV© 2015, iText Group NV Use case: iText 7  New insights  Lessons Learned
  • 31. © 2016, iText Group NV Making development future-proof New insights that led to a complete rewrite of iText 7 Make it modular, make it extensible Remove functional overlap to avoid maintenance hell Meet customer requests, e.g. special writing systems Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText31
  • 32. © 2016, iText Group NV Big bang release or early release? Big bang: what if we got it wrong? Early release: heavy burden on support • Release early for selected users • Release as open source • As soon as the API is stable • Before the work is completely done Something in-between: Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText32
  • 33. © 2016, iText Group NV© 2015, iText Group NV Questions?
  • 34. © 2016, iText Group NV Hello World: iText 5 public void createPdf(String dest) throws DocumentException, IOException { Document document = new Document(); PdfWriter.getInstance( document, new FileOutputStream(dest)); document.open(); document.add(new Paragraph("Hello World!")); document.close(); } Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText34
  • 35. © 2016, iText Group NV Hello World: iText 7 (example 1) public void createPdf(String dest) throws IOException { PdfDocument pdf = new PdfDocument(new PdfWriter(dest)); Document document = new Document(pdf); document.add(new Paragraph("Hello World!")); document.close(); } Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText35
  • 36. © 2016, iText Group NV Hello World: iText 7 (example 2) public void createPdf(String dest) throws IOException { PdfDocument pdf = new PdfDocument(new PdfWriter(dest)); try (Document document = new Document(pdf)) { document.add(new Paragraph("Hello World!")); } } Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText36
  • 37. © 2016, iText Group NV Hello World: iText 5 vs iText 7 Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText37
  • 38. © 2016, iText Group NV Fonts: iText 5 Font font = new Font(FontFamily.TIMES_ROMAN); Font font14pt = new Font(FontFamily.TIMES_ROMAN, 14); Font font10pt = new Font(FontFamily.TIMES_ROMAN, 10); BaseFont bf_russian = BaseFont.createFont( "resources/fonts/FreeSans.ttf", "CP1251", BaseFont.EMBEDDED); Font russian = new Font(bf_russian, 12); BaseFont bf_cjk = BaseFont.createFont( "resources/fonts/NotoSansCJKsc-Regular.otf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED); Font cjk = new Font(bf_cjk, 12); Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText38
  • 39. © 2016, iText Group NV Fonts: iText 7 PdfFont font = PdfFontFactory.createFont(FontConstants.TIMES_ROMAN); PdfFont russian = PdfFontFactory.createFont( "src/main/resources/fonts/FreeSans.ttf", "CP1251", true); PdfFont cjk = PdfFontFactory.createFont( "src/main/resources/fonts/NotoSansCJKsc-Regular.otf", PdfEncodings.IDENTITY_H, true); Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText39
  • 40. © 2016, iText Group NV Fonts: iText 5 Paragraph p = new Paragraph("Hello World! ", font); Chunk chunk = new Chunk("Hallo Wereld! ", font14pt); p.add(chunk); chunk = new Chunk("Bonjour le monde! ", font10pt); chunk.setTextRise(4); p.add(chunk); chunk = new Chunk("u0417u0434 ... u0440! ", russian); p.add(chunk); p.add(new Chunk("u4f60u597du4e16u754c! ", cjk)); p.add(new Chunk("uc5ecubcf4 ... uacc4!", cjk)); document.add(p); Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText40
  • 41. © 2016, iText Group NV Fonts: iText 7 document.setFont(font); Paragraph p = new Paragraph("Hello World! ") .add(new Text("Hallo Wereld! ") .setFontSize(14)) .add( new Text("Bonjour le monde! ") .setFontSize(10) .setTextRise(4)) .add( new Text ("u0417u0434 ... u0440! “).setFont(russian)) .add( new Text("u4f60u597du4e16u754c! ").setFont(cjk)) .add( new Text("uc5ecubcf4 ... uacc4!").setFont(cjk)); document.add(p); Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText41
  • 42. © 2016, iText Group NV Fonts: iText 5 vs iText 7 Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText42
  • 43. © 2016, iText Group NV Switching styles: iText 5 public Chunk createBgChunk(String s, Font font) { Chunk chunk = new Chunk(s, font); chunk.setBackground(BaseColor.LIGHT_GRAY); return chunk; } Font code = new Font( FontFamily.COURIER, 12, Font.NORMAL, BaseColor.RED); Paragraph p = new Paragraph("In this example, named "); p.add(createBgChunk("HelloWorldStyles", code)); p.add(", we experiment with some text in "); p.add(createBgChunk("code style", code)); p.add("."); Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText43
  • 44. © 2016, iText Group NV Switching styles: iText 7 Style style = new Style() .setFont(code) .setFontSize(12) .setFontColor(Color.RED) .setBackgroundColor(Color.LIGHT_GRAY); document.add( new Paragraph() .add("In this example, named ") .add(new Text("HelloWorldStyles").addStyle(style)) .add(", we experiment with some text in ") .add(new Text("code style").addStyle(style)) .add(".")); Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText44
  • 45. © 2016, iText Group NV Switching styles: iText 5 vs iText 7 Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText45
  • 46. © 2016, iText Group NV Tables: iText 5 PdfPTable table = new PdfPTable(3); PdfPCell cell = new PdfPCell(new Phrase("Cell with colspan 3")); cell.setColspan(3); cell.setHorizontalAlignment(Element.ALIGN_CENTER); table.addCell(cell); cell = new PdfPCell(new Phrase("Cell with rowspan 2")); cell.setRowspan(2); cell.setVerticalAlignment(Element.ALIGN_MIDDLE); table.addCell(cell); Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText46
  • 47. © 2016, iText Group NV Tables: iText 5 // text mode table.addCell("Cell 1.1"); // composite mode cell = new PdfPCell(); cell.addElement(new Phrase("Cell 1.2")); table.addCell(cell); Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText47
  • 48. © 2016, iText Group NV Tables: iText 5 cell = new PdfPCell(new Phrase("Cell 2.1")); cell.setPadding(5); cell.setUseAscender(true); cell.setUseDescender(true); cell.setHorizontalAlignment(Element.ALIGN_CENTER); table.addCell(cell); cell = new PdfPCell(); cell.setPadding(5); cell.setUseAscender(true); cell.setUseDescender(true); Paragraph p = new Paragraph("Cell 2.2"); p.setAlignment(Element.ALIGN_CENTER); cell.addElement(p); table.addCell(cell); Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText48
  • 49. © 2016, iText Group NV Tables: iText 7 Table table = new Table(3); Cell cell = new Cell(1, 3) .setTextAlignment(TextAlignment.CENTER) .add("Cell with colspan 3"); table.addCell(cell); cell = new Cell(2, 1) .add("Cell with rowspan 2") .setVerticalAlignment(VerticalAlignment.MIDDLE); table.addCell(cell); Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText49
  • 50. © 2016, iText Group NV Tables: iText 7 table.addCell("Cell 1.1"); table.addCell(new Cell().add("Cell 1.2")); table.addCell(new Cell() .add("Cell 2.1") .setBackgroundColor(Color.LIGHT_GRAY) .setMargin(5)); table.addCell(new Cell() .add("Cell 1.2") .setBackgroundColor(Color.LIGHT_GRAY) .setPadding(5)); Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText50
  • 51. © 2016, iText Group NV Tables: iText 5 vs iText 7 Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText51
  • 52. © 2016, iText Group NV TXT 2 PDF: iText 5 Document document = new Document(); PdfWriter.getInstance(document, new FileOutputStream(dest)); document.open(); BufferedReader br = new BufferedReader(new FileReader(TEXT)); String line; Paragraph p; Font normal = new Font(FontFamily.TIMES_ROMAN, 12); Font bold = new Font(FontFamily.TIMES_ROMAN, 12, Font.BOLD); boolean title = true; while ((line = br.readLine()) != null) { p = new Paragraph(line, title ? bold : normal); p.setAlignment(Element.ALIGN_JUSTIFIED); title = line.isEmpty(); document.add(p); } document.close(); Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText52
  • 53. © 2016, iText Group NV TXT 2 PDF: iText 7 PdfDocument pdf = new PdfDocument(new PdfWriter(dest)); Document document = new Document(pdf) .setTextAlignment(TextAlignment.JUSTIFIED); BufferedReader br = new BufferedReader(new FileReader(TEXT)); String line; PdfFont normal = PdfFontFactory.createFont(FontConstants.TIMES_ROMAN); PdfFont bold = PdfFontFactory.createFont(FontConstants.TIMES_BOLD); boolean title = true; while ((line = br.readLine()) != null) { document.add(new Paragraph(line).setFont(title ? bold : normal)); title = line.isEmpty(); } document.close(); Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText53
  • 54. © 2016, iText Group NV TXT 2 PDF: iText 5 vs iText 7 Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText54
  • 55. © 2016, iText Group NV Columns: iText 5 Document document = new Document(); PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(dest)); document.open(); ColumnText ct = new ColumnText(writer.getDirectContent()); Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText55
  • 56. © 2016, iText Group NV Columns: iText 5 BufferedReader br = new BufferedReader(new FileReader(TEXT)); String line; Paragraph p; Font normal = new Font(FontFamily.TIMES_ROMAN, 12); Font bold = new Font(FontFamily.TIMES_ROMAN, 12, Font.BOLD); boolean title = true; while ((line = br.readLine()) != null) { p = new Paragraph(line, title ? bold : normal); p.setAlignment(Element.ALIGN_JUSTIFIED); title = line.isEmpty(); ct.addElement(p); } Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText56
  • 57. © 2016, iText Group NV Columns: iText 5 Rectangle[] columns = { new Rectangle(36, 36, 290, 806), new Rectangle(305, 36, 559, 806) } int c = 0; int status = ColumnText.START_COLUMN; while (ColumnText.hasMoreText(status)) { ct.setSimpleColumn(columns[c]); status = ct.go(); if (++c == 2) { document.newPage(); c = 0; } } document.close(); Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText57
  • 58. © 2016, iText Group NV Columns: iText 7 PdfDocument pdf = new PdfDocument(new PdfWriter(dest)); Document document = new Document(pdf) .setTextAlignment(TextAlignment.JUSTIFIED); Rectangle[] columns = { new Rectangle(36, 36, 254, 770), new Rectangle(305, 36, 254, 770) }; document.setRenderer(new ColumnDocumentRenderer(document, columns)); BufferedReader br = new BufferedReader(new FileReader(TEXT)); String line; PdfFont normal = PdfFontFactory.createFont(FontConstants.TIMES_ROMAN); PdfFont bold = PdfFontFactory.createFont(FontConstants.TIMES_BOLD); boolean title = true; while ((line = br.readLine()) != null) { document.add(new Paragraph(line).setFont(title ? bold : normal)); title = line.isEmpty(); } document.close(); Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText58
  • 59. © 2016, iText Group NV Columns: iText 5 vs iText 7 Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText59
  • 60. © 2016, iText Group NV Page events: iText 5 Document document = new Document(); PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(dest)); MyPageEvents events = new MyPageEvents(); writer.setPageEvent(events); document.open(); Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText60
  • 61. © 2016, iText Group NV Page events: iText 5 BufferedReader br = new BufferedReader(new FileReader(TEXT)); String line; Paragraph p; Font normal = new Font(FontFamily.TIMES_ROMAN, 12); Font bold = new Font(FontFamily.TIMES_ROMAN, 12, Font.BOLD); boolean title = true; while ((line = br.readLine()) != null) { p = new Paragraph(line, title ? bold : normal); p.setAlignment(Element.ALIGN_JUSTIFIED); events.setTitle(title); document.add(p); title = line.isEmpty(); } document.close(); Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText61
  • 62. © 2016, iText Group NV Page events: iText 5 class MyPageEvents extends PdfPageEventHelper { protected float startpos = -1; protected boolean title = true; public void setTitle(boolean title) { this.title = title; } @Override public void onEndPage(PdfWriter writer, Document document) { ... } @Override public void onParagraph(PdfWriter writer, Document document, float paragraphPosition) { ... } @Override public void onParagraphEnd(PdfWriter writer, Document document, float paragraphPosition) { ... } } Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText62
  • 63. © 2016, iText Group NV Page events: iText 5 @Override public void onEndPage(PdfWriter writer, Document document) { Rectangle pagesize = document.getPageSize(); ColumnText.showTextAligned( writer.getDirectContent(), Element.ALIGN_CENTER, new Phrase(String.valueOf(writer.getPageNumber())), (pagesize.getLeft() + pagesize.getRight()) / 2, pagesize.getBottom() + 15, 0); if (startpos != -1) onParagraphEnd(writer, document, pagesize.getBottom(document.bottomMargin())); startpos = pagesize.getTop(document.topMargin()); } Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText63
  • 64. © 2016, iText Group NV Page events: iText 5 @Override public void onParagraph(PdfWriter writer, Document document, float paragraphPosition) { startpos = paragraphPosition; } @Override public void onParagraphEnd(PdfWriter writer, Document document, float paragraphPosition) { if (!title) return; PdfContentByte canvas = writer.getDirectContentUnder(); Rectangle pagesize = document.getPageSize(); canvas.saveState(); canvas.setColorStroke(BaseColor.BLUE); canvas.rectangle( pagesize.getLeft(document.leftMargin()), paragraphPosition - 3, pagesize.getWidth() - document.leftMargin() - document.rightMargin(), startpos - paragraphPosition); canvas.stroke(); canvas.restoreState(); } Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText64
  • 65. © 2016, iText Group NV Event handlers: iText 7 PdfDocument pdf = new PdfDocument(new PdfWriter(dest)); pdf.addEventHandler(PdfDocumentEvent.END_PAGE, new Footer()); Document document = new Document(pdf).setTextAlignment(TextAlignment.JUSTIFIED); BufferedReader br = new BufferedReader(new FileReader(TEXT)); String line; PdfFont normal = PdfFontFactory.createFont(FontConstants.TIMES_ROMAN); PdfFont bold = PdfFontFactory.createFont(FontConstants.TIMES_BOLD); boolean title = true; Border border = new SolidBorder(Color.BLUE, 1); while ((line = br.readLine()) != null) { document.add(new Paragraph(line) .setFont(title ? bold : normal) .setBorder(title ? border : Border.NO_BORDER)); title = line.isEmpty(); } document.close(); Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText65
  • 66. © 2016, iText Group NV Event handlers: iText 7 protected class Footer implements IEventHandler { @Override public void handleEvent(Event event) { PdfDocumentEvent docEvent = (PdfDocumentEvent) event; PdfDocument pdf = docEvent.getDocument(); PdfPage page = docEvent.getPage(); Rectangle pageSize = page.getPageSize(); PdfCanvas pdfCanvas = new PdfCanvas( page.getLastContentStream(), page.getResources(), pdf); Canvas canvas = new Canvas(pdfCanvas, pdf, pageSize); float x = (pageSize.getLeft() + pageSize.getRight()) / 2; float y = pageSize.getBottom() + 15; canvas.showTextAligned( String.valueOf(pdf.getPageNumber(page)), x, y, TextAlignment.CENTER); } } Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText66
  • 67. © 2016, iText Group NV Events: iText 5 vs iText 7 Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText67
  • 68. © 2016, iText Group NV Renderers: iText 7 public class TitleParagraph extends Paragraph { public TitleParagraph(String line) { super(line); try { setFont(PdfFontFactory.createFont(FontConstants.TIMES_BOLD)); } catch (IOException ioe) { } } @Override protected IRenderer makeNewRenderer() { return new ParagraphRenderer(this) { ... }; } } Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText68
  • 69. © 2016, iText Group NV Renderers: iText 7 @Override public void drawBorder(DrawContext drawContext) { Rectangle occupiedAreaBBox = getOccupiedAreaBBox(); float[] margins = getMargins(); Rectangle rectangle = applyMargins(occupiedAreaBBox, margins, false); PdfCanvas canvas = drawContext.getCanvas(); canvas.roundRectangle(rectangle.getX() - 1, rectangle.getY() - 1, rectangle.getWidth() + 2, rectangle.getHeight() + 2, 5).stroke(); } Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText69
  • 70. © 2016, iText Group NV Renderers: iText 5 vs iText 7 Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText70
  • 71. © 2016, iText Group NV Form creation: iText 5 PdfReader reader = new PdfReader(src); PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest)); TextField tf = new TextField(stamper.getWriter(), new Rectangle(110, 780, 180, 806), "text"); tf.setBorderColor(BaseColor.BLUE); tf.setBorderWidth(2); tf.setTextColor(BaseColor.RED); tf.setFontSize(12); tf.setText("Text field"); PdfFormField field = tf.getTextField(); stamper.addAnnotation(field, 1); stamper.close(); reader.close(); Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText71
  • 72. © 2016, iText Group NV Form creation: iText 7 PdfReader reader = new PdfReader(src); PdfDocument pdf = new PdfDocument(reader, new PdfWriter(dest)); PdfAcroForm form = PdfAcroForm.getAcroForm(pdf, true); PdfFormField tf = PdfTextFormField.createText(pdf, new Rectangle(110, 780, 70, 26), "text", "Text Field") .setBorderColor(Color.BLUE) .setBorderWidth(2) .setColor(Color.RED) .setFontSize(12); form.addField(tf); pdf.close(); Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText72
  • 73. © 2016, iText Group NV Form creation: iText 5 vs iText 7 Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText73
  • 74. © 2016, iText Group NV Form filling: iText 5 PdfReader reader = new PdfReader(src); PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest)); AcroFields fields = stamper.getAcroFields(); fields.setFieldProperty("text", "textcolor", BaseColor.BLUE, null); fields.setFieldProperty("text", "bordercolor", BaseColor.RED, null); fields.setFieldProperty("text", "fontsize", 14, null); fields.setField("text", "Field Text"); stamper.close(); reader.close(); Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText74
  • 75. © 2016, iText Group NV Form filling: iText 7 PdfReader reader = new PdfReader(src); PdfDocument pdf = new PdfDocument(reader, new PdfWriter(dest)); PdfAcroForm form = PdfAcroForm.getAcroForm(pdf, true); PdfFormField tf = form.getFormFields().get("text"); tf.setBorderColor(Color.RED) .setColor(Color.BLUE) .setFontSize(14) .setValue("Field Text"); pdf.close(); Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText75
  • 76. © 2016, iText Group NV Form filling: iText 5 vs iText 7 Oops, I broke my API - JavaOne 2016: @bruno1970, @rafhens, @iText76

Notas del editor

  1. What is it? In computing, backwards or downwards compatibility is a general term referring to the ability to read, write, and/or execute input with a certain technology, where that input was designed to be read, written, and/or executed by an older version of the same technology. Example 1: Java In the Java programming language, code written according to the Java 1.0 specification will still run with identical results on the current version (*), and it is generally understood that this will be so indefinitely. Innovations have been made in the succeeding major versions of the Java language, mostly by expanding the available syntax, but the original specification is still 100% valid. Example 2: PDF PDFs created in an old PDF format (e.g. PDF 1.0) should be rendered correctly by later viewers. Newer versions of PDF add new functionality. They don’t remove existing functionality (*). An older PDF viewer might not be able to use that new functionality (e.g. OCG), or even fail to render the document (e.g. when the cross-reference table is compressed). Important: Backward compatibility obviously doesn’t mean you can run newer code in an older environment. For instance: code compiled with Java 8 can cause a java.lang.UnsupportedClassVersionError (Unsupported major.minor version) when you run it on a Java 6 JVM, even if you only use functionality that was already available in Java 6. In context of a library, the “input” is the application code calling the API.
  2. Mention “Bug compatibility”: emulation of bugs may be necessary if legacy code depends on that behavior
  3. BouncyCastle The Android operating system, as of early 2014, includes a customized version of Bouncy Castle. Due to class name conflicts, this prevents Android applications from including and using the official release of Bouncy Castle as-is. A third-party project called Spongy Castle distributes a renamed version of the library to work around this issue. iText 4 A third party created a fork of iText 2.1.7 and named it iText 4. That’s fine, but unfortunately they also released this unofficial version on Maven using the official iText groupId. That’s not OK: according to the Apache FAQ, this is in violation with the rules. Many users upgraded to iText 4 without realizing they were using an unofficial iText version. Nevertheless, they expected the original iText developers to support this version. iText Group reclaimed its groupId and this broke the Maven builds of many iText 4 users. Some developers blamed iText for this, instead of blaming the real culprits. I removed this example: OpenSSL At 11 PM on new year’s eve 2011, David Henson received the code from Robin Seggelmann, a respected academic who’s an expert in internet protocols. Henson reviewed the code and had added it to the OpenSSL repository. More than two years later, in April 2014, this patch was discovered to cause a serious security vulnerability known as “Heartbleed”, impacting almost every company using OpenSSL.
  4. Try to fix problems with internal re-implementations Do not change the API that is exposed to the developers. Sometimes parts of the API were not intended to be exposed. Java 9 will allow to encapsulate internal APIs Use two methods for the same function, deprecate the old method Main disadvantage: redundancy E.g. in PDF: the F operator is equivalent to the f operator. It’s there for historical reasons and should no longer be used.
  5. XFA There were dozens of ways to construct a similar form. Even Adobe didn’t succeed in following its own spec. Almost no third party vendor supported XFA because it was too complex. As a result, XFA was deprecated in ISO-32000-2. A PDF 2.0 file shall not contain any XFA. Python An official goal of the Python 3 redesign was to "reduce feature duplication by removing old ways of doing things". An example is the use of placeholders in string templates iText E.g. in iText: the HTMLWorker class was deprecated in favor of the XML Worker framework. HTMLWorker was written for a specific, limited purpose, but people started to use it in a broader way. We get plenty of questions from people who use HTMLWorker and want us to extend it. We can’t and won’t do that. In iText 5, there were several rendering APIs that had a lot of functional overlap but also showed (sometimes subtle) differences in behavior In iText 7, we introduced a renderer framework that is much easier to maintain
  6. Digital signatures depend on hashing and encryption algorithms Algorithms are subject to flaws and vulnerabilities: e.g. collision attacks in MD5, SHA-1... Processing power increases, reducing the time to decrypt a message Internationalization: ASCII isn’t sufficient anymore, we need Unicode Python 2 depended on ASCII; the API of Python 3 was changed in favor of Unicode Standards and specifications change For instance: the maximum file size in PDF file used to be 10 Gigabyte, this was increased to 1 Terabyte, but to achieve this, the PDF needs to have a compressed cross-reference table with a different structure than before. Old viewers can’t read such a cross-reference table. Before iText 5.2.0, all byte positions were expressed in int. This reduced the maximum file size of a PDF to 2 Gigabyte. We changed int to long to support files up to 1 Terabyte. No API change was required, but we broke the 5.2.x series by accident. We removed all 5.2.x releases from our repositories.
  7. Twitter The easy API provided by Twitter caused a couple of problems It resulted in huge server loads (we all know the “fail whale”) It was easy to use the API in ways that weren’t acceptable (SPAM, abuse) In 2013, the API was changed to restrict access to authenticated, registered applications Sharepoint Sharepoint 2010: IFilter architecture, for instance to search PDF files in an intelligent way Adobe (free), PDFLib, and Foxit were better than MS at searching PDF files in Sharepoint Sharepoint 2013: IFilter support for PDF is broken PDF “natively” supported in Sharepoint by MS; competing products no longer work, no longer needed
  8. iText 7 versus iText 5 The core design hadn’t changed since 2000. The original design and first versions were written by a self-taught developer Not enough refactoring along the way. Breaking compatibility gradually from time to time could have prevented the complete iText 7 rewrite. Younger code (e.g. digital signatures, parsing PDF) can be reused; the older code needed a rewrite We gained new insights thanks to people using iText in ways we didn’t expect E.g. the original developer never imagined that one day he’d have to support Hindi iText grew organically; many different developers contributed E.g. form fields: different classes for form creation vs. form filling E.g. different layout systems: Document.add() vs. ColumnText vs. writing to PdfContentByte The world has changed since 2000: People started deploying applications on AWS and GAE: different file system. People started using iText on Android: monolithic iText vs. limitation of the number of classes
  9. BouncyCastle: Source code incompatibilities were introduced in version 1.47. This led to numerous problems for all libraries that had a dependency on BouncyCastle 1.x. The communication wasn’t ideal: “The next release of BC will be version 2.0. For this reason a lot of things in 1.46 that relate to CMS have been deprecated” (Bouncy Castle Release Notes 1.46, 2011) “Okay, so we have had to do another release. The issue we have run into is that we probably didn’t go far enough in 1.46, but we are now confident that moving from this release to 2.0 should be largely just getting rid of deprecated methods.” (Bouncy Castle Release Notes 1.47, 2012) “There has been further clean out of deprecated methods in this release. If your code has previously been flagged as using a deprecated method you may need to change it. The OpenPGP API is the most heavily affected.” (Bouncy Castle Release Notes 1.51, 2014) The most recent version is currently 1.54, dating from 2015. BouncyCastle 2.0 never happened. iText 7 also doesn’t strictly use semantic versioning, but we intend to do something similar.
  10. Spring 2 evolving into Spring 3 Configuration in Spring 2 was done using XML XML used to be popular, but its popularity faded over the years Spring 3 added configuration through annotations without breaking the API The original design of the Spring Framework was future-proof Python 3 versus Python 2 There were several integer sizes in memory, one of which was dependent on the architecture of the underlying processor The exception framework was inconsistent and idiosyncratic Comparison of object types was complex and non-intuitive But also… trade off between being future proof / well designed and pragmatic / performant.
  11. We kept project Arya closed source until we were confident there wouldn’t be any substantial changes to the API Writing the jump-start tutorial was a pain, because the examples and the text of the tutorial had to be updated on a regular basis Commons-imaging: our mistake to depend on a snapshot version
  12. * Clirr (http://clirr.sourceforge.net/) ** Clirr Maven plugin *** console: mvn clirr:check *** we run it in a separate profile ** Clirr SonarQube plugin *** browser *** Tip: create separate SQ dashboard   * JDiff (http://javadiff.sourceforge.net/) ** Javadoc doclet ** generates HTML report of API differences ** published for users
  13. Provide good documentation Provide conversion tools Python: To move from Python 2 to Python 3, a tool called 2to3 was developed to make the transition easier, essentially rewriting Python 2 source code to fit the Python 3 specification specific user-contributed package called six, which users can add to their Python project of either version to make it reusable on the other version Microsoft Word The .doc and newer .docx document formats for Microsoft Word are not mutually compatible. However, the versions of MS Word since the introduction of .docx are still able to open and edit .doc files usually suggesting to save the document to the newer format to make the file more future-proof.
  14. Python a number of Python 3 innovations have been back-ported to the Python 2 project. This takes away incentive for developers to make the switch at all, because the new features are no longer exclusive to Python 3. As a consequence of the stability of and continued development on Python 2, uptake of Python 3 has been relatively slow. iText No new development in iText 5, only bug fixing All new functionality will be developed in iText 7 Maintaining multiple versions means less resource for new developments in the new version. In open source you cannot prevent/prohibit back-porting. Users may fork. They should mainly be discouraged to do so because they are convinced by the new version.
  15. Python 3 was released in 2008. Announcement that Python 2 would be supported until 2020 was made in 2014. That EOL date has changed many times.
  16. UWP: the Universal Windows Platform Released in 2015 The announcement of UWP felt as a huge marketing event There were talks and articles on “How to monetize your app” There was very little technical info UWP is based on the .NET Core, but the API of .NET Core wasn’t backward compatible to the .NET Framework Moreover: it wasn’t ready when UWP was announced. It was a moving target. A general porting guide was released in February 2016, but it stays clear of giving exact advice on some of the more fundamental changes in the .NET Core reimplementation, like the Cryptography implementation. This is problematic for vendors confronted with questions such as “Is there UWP support for iText?” We know what breaks, but it’s not clear how to fix it. Stream::Close() doesn’t exist anymore: replaced by Stream::Dispose() (from IDisposable) System.Text.Encoding has changed the names of several properties ICloneable doesn’t exist anymore MethodImplOptions.Synchronized doesn’t exist anymore Serializable and SerializationInfo don’t exist anymore The entire System.util namespace doesn’t exist anymore TimeZone doesn’t exist anymore System.Xml.XmlTextReader and XPath APIs don’t exist anymore …
  17. Deprecate before deleting The user thus receives a fair warning that it is unwise to reference that code in their client application, usually with the implication that the faulty code may be deleted at any time Warn that the code is subject to change Sun packages: example PKCS#11 The class sun.security.pkcs11.SunPKCS11 was available in the 32-bit version of Java 6, but not in the 64-bit version Beware of non-technical API changes iText 2: the MPL/LGPL made it hard to find a working business model iText 5: the AGPL allowed us to create a business based on a dual licensing model We had to make sure that users didn’t accidentally upgrade, so we broke the API The package names com.lowagie were changed into com.itextpdf
  18. New insights that led to a complete rewrite of iText 7 Make it modular, make it extensible Some users complained that they only needed a small part of the functionality, but still had to ship the full, monolithic iText jar with their applications. The original design was extensible, otherwise it wouldn’t have lasted for 16 years, but there was room for improvement. Allow the introduction of a new business model: iText 7 as a platform. Remove functional overlap to avoid maintenance hell You change something in one place, but forget to change it in another place