From 19b3e47972ddc6558dc9010edf9dce761d96f98e Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Thu, 13 Jul 2017 20:20:49 -0400 Subject: [PATCH 1/2] Fix casting error during initialization While running scripted, you see ``` ERROR StatusLogger Unable to create custom ContextSelector. Falling back to default. java.lang.ClassCastException: Cannot cast org.apache.logging.log4j.core.async.AsyncLoggerContextSelector to org.apache.logging.log4j.core.selector.ContextSelector at java.lang.Class.cast(Class.java:3369) at org.apache.logging.log4j.util.LoaderUtil.newCheckedInstanceOf(LoaderUtil.java:201) at org.apache.logging.log4j.util.LoaderUtil.newCheckedInstanceOfProperty(LoaderUtil.java:226) at org.apache.logging.log4j.core.impl.Log4jContextFactory.createContextSelector(Log4jContextFactory.java:97) at org.apache.logging.log4j.core.impl.Log4jContextFactory.(Log4jContextFactory.java:58) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at java.lang.Class.newInstance(Class.java:442) at org.apache.logging.log4j.LogManager.(LogManager.java:94) at org.apache.logging.log4j.spi.ThreadContextMapFactory.createThreadContextMap(ThreadContextMapFactory.java:73) at org.apache.logging.log4j.ThreadContext.init(ThreadContext.java:223) at org.apache.logging.log4j.ThreadContext.(ThreadContext.java:202) at org.apache.logging.log4j.core.impl.ContextDataInjectorFactory.createDefaultInjector(ContextDataInjectorFactory.java:83) at org.apache.logging.log4j.core.impl.ContextDataInjectorFactory.createInjector(ContextDataInjectorFactory.java:67) at org.apache.logging.log4j.core.lookup.ContextMapLookup.(ContextMapLookup.java:34) at org.apache.logging.log4j.core.lookup.Interpolator.(Interpolator.java:117) at org.apache.logging.log4j.core.config.AbstractConfiguration.(AbstractConfiguration.java:125) at org.apache.logging.log4j.core.config.DefaultConfiguration.(DefaultConfiguration.java:46) at org.apache.logging.log4j.core.layout.PatternLayout$Builder.build(PatternLayout.java:650) at org.apache.logging.log4j.core.layout.PatternLayout.createDefaultLayout(PatternLayout.java:487) at sbt.internal.util.ConsoleAppender.(ConsoleAppender.scala:245) ``` This aims to workaround the casting error during PatternLayout.createDefaultLayout() that was originally used for ConsoleAppender. The stacktrace shows it's having issue initializing default DefaultConfiguration. Since we currently do not use Layout inside ConsoleAppender, the actual pattern is not relevant. --- .../sbt/internal/util/ConsoleAppender.scala | 3 +-- .../src/main/scala/sbt/util/LogExchange.scala | 20 ++++++++++++++++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/internal/util-logging/src/main/scala/sbt/internal/util/ConsoleAppender.scala b/internal/util-logging/src/main/scala/sbt/internal/util/ConsoleAppender.scala index e85f70fa8..75ca7146e 100644 --- a/internal/util-logging/src/main/scala/sbt/internal/util/ConsoleAppender.scala +++ b/internal/util-logging/src/main/scala/sbt/internal/util/ConsoleAppender.scala @@ -8,7 +8,6 @@ import org.apache.logging.log4j.{ Level => XLevel } import org.apache.logging.log4j.message.{ Message, ObjectMessage, ReusableObjectMessage } import org.apache.logging.log4j.core.{ LogEvent => XLogEvent } import org.apache.logging.log4j.core.appender.AbstractAppender -import org.apache.logging.log4j.core.layout.PatternLayout import ConsoleAppender._ @@ -242,7 +241,7 @@ class ConsoleAppender private[ConsoleAppender] ( val ansiCodesSupported: Boolean, val useColor: Boolean, val suppressedMessage: SuppressedTraceContext => Option[String] -) extends AbstractAppender(name, null, PatternLayout.createDefaultLayout(), true) { +) extends AbstractAppender(name, null, LogExchange.dummyLayout, true) { import scala.Console.{ BLUE, GREEN, RED, RESET, YELLOW } def append(event: XLogEvent): Unit = diff --git a/internal/util-logging/src/main/scala/sbt/util/LogExchange.scala b/internal/util-logging/src/main/scala/sbt/util/LogExchange.scala index 1dc17804d..150814bc5 100644 --- a/internal/util-logging/src/main/scala/sbt/util/LogExchange.scala +++ b/internal/util-logging/src/main/scala/sbt/util/LogExchange.scala @@ -5,6 +5,7 @@ import org.apache.logging.log4j.{ LogManager => XLogManager, Level => XLevel } import org.apache.logging.log4j.core._ import org.apache.logging.log4j.core.appender.AsyncAppender import org.apache.logging.log4j.core.config.{ AppenderRef, LoggerConfig } +import org.apache.logging.log4j.core.layout.PatternLayout import scala.collection.JavaConverters._ import scala.collection.concurrent import sjsonnew.JsonFormat @@ -47,6 +48,22 @@ sealed abstract class LogExchange { val config = ctx.getConfiguration config.getLoggerConfig(loggerName) } + + // This is a dummy layout to avoid casting error during PatternLayout.createDefaultLayout() + // that was originally used for ConsoleAppender. + // The stacktrace shows it's having issue initializing default DefaultConfiguration. + // Since we currently do not use Layout inside ConsoleAppender, the actual pattern is not relevant. + private[sbt] lazy val dummyLayout: PatternLayout = { + val _ = context + val ctx = XLogManager.getContext(false) match { case x: LoggerContext => x } + val config = ctx.getConfiguration + val lo = PatternLayout.newBuilder + .withConfiguration(config) + .withPattern(PatternLayout.SIMPLE_CONVERSION_PATTERN) + .build + lo + } + def jsonCodec[A](tag: String): Option[JsonFormat[A]] = jsonCodecs.get(tag) map { _.asInstanceOf[JsonFormat[A]] } def hasJsonCodec(tag: String): Boolean = @@ -63,9 +80,6 @@ sealed abstract class LogExchange { private[sbt] def buildAsyncStdout: AsyncAppender = { val ctx = XLogManager.getContext(false) match { case x: LoggerContext => x } val config = ctx.getConfiguration - // val layout = PatternLayout.newBuilder - // .withPattern(PatternLayout.SIMPLE_CONVERSION_PATTERN) - // .build val appender = ConsoleAppender("Stdout") // CustomConsoleAppenderImpl.createAppender("Stdout", layout, null, null) appender.start From 18a73db57d8699d487918ed0ad441db3d3848854 Mon Sep 17 00:00:00 2001 From: jvican Date: Thu, 22 Jun 2017 20:46:23 +0200 Subject: [PATCH 2/2] Remove unnecessary F0, F1 and Maybe `F0`, `F1` and `Maybe` have become useless since Java 8 introduced `Supplier`, `Function` and `Optional` in the default Java 8 standard library. Therefore, they are not necessary anymore. This change is required to change some Zinc's and sbt APIs. They are not widely used, so the changes will be small. --- .../src/main/java/xsbti/F0.java | 9 ---- .../src/main/java/xsbti/F1.java | 6 --- .../src/main/java/xsbti/Logger.java | 15 +++--- .../src/main/java/xsbti/Maybe.java | 48 ------------------- .../main/scala/sbt/util/InterfaceUtil.scala | 33 +++++++------ .../src/main/scala/sbt/util/Logger.scala | 42 ++++++++-------- 6 files changed, 45 insertions(+), 108 deletions(-) delete mode 100644 internal/util-interface/src/main/java/xsbti/F0.java delete mode 100644 internal/util-interface/src/main/java/xsbti/F1.java delete mode 100644 internal/util-interface/src/main/java/xsbti/Maybe.java diff --git a/internal/util-interface/src/main/java/xsbti/F0.java b/internal/util-interface/src/main/java/xsbti/F0.java deleted file mode 100644 index b0091b186..000000000 --- a/internal/util-interface/src/main/java/xsbti/F0.java +++ /dev/null @@ -1,9 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2009 Mark Harrah - */ -package xsbti; - -public interface F0 -{ - T apply(); -} diff --git a/internal/util-interface/src/main/java/xsbti/F1.java b/internal/util-interface/src/main/java/xsbti/F1.java deleted file mode 100644 index 8797e9196..000000000 --- a/internal/util-interface/src/main/java/xsbti/F1.java +++ /dev/null @@ -1,6 +0,0 @@ -package xsbti; - -public interface F1 -{ - R apply(A1 a1); -} diff --git a/internal/util-interface/src/main/java/xsbti/Logger.java b/internal/util-interface/src/main/java/xsbti/Logger.java index 60dfab7b5..1e9539fe7 100644 --- a/internal/util-interface/src/main/java/xsbti/Logger.java +++ b/internal/util-interface/src/main/java/xsbti/Logger.java @@ -3,11 +3,12 @@ */ package xsbti; -public interface Logger -{ - void error(F0 msg); - void warn(F0 msg); - void info(F0 msg); - void debug(F0 msg); - void trace(F0 exception); +import java.util.function.Supplier; + +public interface Logger { + void error(Supplier msg); + void warn(Supplier msg); + void info(Supplier msg); + void debug(Supplier msg); + void trace(Supplier exception); } diff --git a/internal/util-interface/src/main/java/xsbti/Maybe.java b/internal/util-interface/src/main/java/xsbti/Maybe.java deleted file mode 100644 index 0c5ea23b8..000000000 --- a/internal/util-interface/src/main/java/xsbti/Maybe.java +++ /dev/null @@ -1,48 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2008, 2009, 2010 Mark Harrah - */ -package xsbti; - -/** Intended as a lightweight carrier for scala.Option. */ -public abstract class Maybe { - private Maybe() {} - - @SuppressWarnings("unchecked") - public static Maybe nothing() { return (Maybe) Nothing.INSTANCE; } - public static Maybe just(final s v) { return new Just(v); } - - public static final class Just extends Maybe { - private final s v; - - public Just(final s v) { this.v = v; } - - public s value() { return v; } - - public boolean isDefined() { return true; } - public s get() { return v; } - public int hashCode() { return 17 + (v == null ? 0 : v.hashCode()); } - public String toString() { return "Maybe.just(" + v + ")"; } - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !(o instanceof Just)) return false; - final Just that = (Just) o; - return v == null ? that.v == null : v.equals(that.v); - } - } - - public static final class Nothing extends Maybe { - public static final Nothing INSTANCE = new Nothing(); - private Nothing() { } - - public boolean isDefined() { return false; } - public Object get() { throw new UnsupportedOperationException("nothing.get"); } - - public int hashCode() { return 1; } - public String toString() { return "Maybe.nothing()"; } - public boolean equals(Object o) { return this == o || o != null && o instanceof Nothing; } - } - - public final boolean isEmpty() { return !isDefined(); } - public abstract boolean isDefined(); - public abstract t get(); -} diff --git a/internal/util-logging/src/main/scala/sbt/util/InterfaceUtil.scala b/internal/util-logging/src/main/scala/sbt/util/InterfaceUtil.scala index 328ba8bc7..63e4213cb 100644 --- a/internal/util-logging/src/main/scala/sbt/util/InterfaceUtil.scala +++ b/internal/util-logging/src/main/scala/sbt/util/InterfaceUtil.scala @@ -1,22 +1,29 @@ package sbt.util -import xsbti.{ Maybe, F0, F1, T2, Position, Problem, Severity } +import xsbti.{ Position, Problem, Severity, T2 } import java.io.File import java.util.Optional +import java.util.function.Supplier object InterfaceUtil { - def f0[A](a: => A): F0[A] = new ConcreteF0[A](a) - def f1[A1, R](f: A1 => R): F1[A1, R] = new ConcreteF1(f) + def toSupplier[A](a: => A): Supplier[A] = new Supplier[A] { + override def get: A = a + } + + import java.util.function.{ Function => JavaFunction } + def toJavaFunction[A1, R](f: A1 => R): JavaFunction[A1, R] = new JavaFunction[A1, R] { + override def apply(t: A1): R = f(t) + } + def t2[A1, A2](x: (A1, A2)): T2[A1, A2] = new ConcreteT2(x._1, x._2) - def m2o[A](m: Maybe[A]): Option[A] = - if (m.isDefined) Some(m.get) - else None + def toOption[A](m: Optional[A]): Option[A] = + if (m.isPresent) Some(m.get) else None - def o2m[A](o: Option[A]): Maybe[A] = + def toOptional[A](o: Option[A]): Optional[A] = o match { - case Some(v) => Maybe.just(v) - case None => Maybe.nothing() + case Some(v) => Optional.of(v) + case None => Optional.empty() } def jo2o[A](o: Optional[A]): Option[A] = @@ -36,14 +43,6 @@ object InterfaceUtil { def problem(cat: String, pos: Position, msg: String, sev: Severity): Problem = new ConcreteProblem(cat, pos, msg, sev) - private final class ConcreteF0[A](a: => A) extends F0[A] { - def apply: A = a - } - - private final class ConcreteF1[A1, R](f: A1 => R) extends F1[A1, R] { - def apply(a1: A1): R = f(a1) - } - private final class ConcreteT2[A1, A2](a1: A1, a2: A2) extends T2[A1, A2] { val get1: A1 = a1 val get2: A2 = a2 diff --git a/internal/util-logging/src/main/scala/sbt/util/Logger.scala b/internal/util-logging/src/main/scala/sbt/util/Logger.scala index fd5b34a60..abcad3428 100644 --- a/internal/util-logging/src/main/scala/sbt/util/Logger.scala +++ b/internal/util-logging/src/main/scala/sbt/util/Logger.scala @@ -3,13 +3,14 @@ */ package sbt.util -import xsbti.{ Logger => xLogger, F0 } -import xsbti.{ Maybe, Position, Problem, Severity } +import xsbti.{ Logger => xLogger } +import xsbti.{ Position, Problem, Severity } + import sys.process.ProcessLogger import sbt.internal.util.{ BufferedLogger, FullLogger } - import java.io.File import java.util.Optional +import java.util.function.Supplier /** * This is intended to be the simplest logging interface for use by code that wants to log. @@ -32,12 +33,12 @@ abstract class Logger extends xLogger { def success(message: => String): Unit def log(level: Level.Value, message: => String): Unit - def debug(msg: F0[String]): Unit = log(Level.Debug, msg) - def warn(msg: F0[String]): Unit = log(Level.Warn, msg) - def info(msg: F0[String]): Unit = log(Level.Info, msg) - def error(msg: F0[String]): Unit = log(Level.Error, msg) - def trace(msg: F0[Throwable]): Unit = trace(msg.apply) - def log(level: Level.Value, msg: F0[String]): Unit = log(level, msg.apply) + def debug(msg: Supplier[String]): Unit = log(Level.Debug, msg) + def warn(msg: Supplier[String]): Unit = log(Level.Warn, msg) + def info(msg: Supplier[String]): Unit = log(Level.Info, msg) + def error(msg: Supplier[String]): Unit = log(Level.Error, msg) + def trace(msg: Supplier[Throwable]): Unit = trace(msg.get()) + def log(level: Level.Value, msg: Supplier[String]): Unit = log(level, msg.get) } object Logger { @@ -67,17 +68,18 @@ object Logger { case _ => wrapXLogger(lg) } private[this] def wrapXLogger(lg: xLogger): Logger = new Logger { - override def debug(msg: F0[String]): Unit = lg.debug(msg) - override def warn(msg: F0[String]): Unit = lg.warn(msg) - override def info(msg: F0[String]): Unit = lg.info(msg) - override def error(msg: F0[String]): Unit = lg.error(msg) - override def trace(msg: F0[Throwable]): Unit = lg.trace(msg) - override def log(level: Level.Value, msg: F0[String]): Unit = lg.log(level, msg) - def trace(t: => Throwable): Unit = trace(f0(t)) - def success(s: => String): Unit = info(f0(s)) + import InterfaceUtil.toSupplier + override def debug(msg: Supplier[String]): Unit = lg.debug(msg) + override def warn(msg: Supplier[String]): Unit = lg.warn(msg) + override def info(msg: Supplier[String]): Unit = lg.info(msg) + override def error(msg: Supplier[String]): Unit = lg.error(msg) + override def trace(msg: Supplier[Throwable]): Unit = lg.trace(msg) + override def log(level: Level.Value, msg: Supplier[String]): Unit = lg.log(level, msg) + def trace(t: => Throwable): Unit = trace(toSupplier(t)) + def success(s: => String): Unit = info(toSupplier(s)) def log(level: Level.Value, msg: => String): Unit = { - val fmsg = f0(msg) + val fmsg = toSupplier(msg) level match { case Level.Debug => lg.debug(fmsg) case Level.Info => lg.info(fmsg) @@ -86,9 +88,7 @@ object Logger { } } } - def f0[A](a: => A): F0[A] = InterfaceUtil.f0[A](a) - def m2o[A](m: Maybe[A]): Option[A] = InterfaceUtil.m2o(m) - def o2m[A](o: Option[A]): Maybe[A] = InterfaceUtil.o2m(o) + def jo2o[A](o: Optional[A]): Option[A] = InterfaceUtil.jo2o(o) def o2jo[A](o: Option[A]): Optional[A] = InterfaceUtil.o2jo(o) def position(line0: Option[Integer], content: String, offset0: Option[Integer], pointer0: Option[Integer],